am 05e7aedd: am 948e7dc0: am e11bafec: Add the test template for the media audio manager test.
diff --git a/api/current.xml b/api/current.xml
index 53f5178..69125d5 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -1802,6 +1802,17 @@
  visibility="public"
 >
 </field>
+<field name="adapter"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843454"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="addStatesFromChildren"
  type="int"
  transient="false"
@@ -2011,6 +2022,17 @@
  visibility="public"
 >
 </field>
+<field name="as"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843460"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="author"
  type="int"
  transient="false"
@@ -2671,6 +2693,17 @@
  visibility="public"
 >
 </field>
+<field name="column"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843463"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="columnDelay"
  type="int"
  transient="false"
@@ -3837,6 +3870,17 @@
  visibility="public"
 >
 </field>
+<field name="from"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843458"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="fromAlpha"
  type="int"
  transient="false"
@@ -3859,6 +3903,17 @@
  visibility="public"
 >
 </field>
+<field name="fromValue"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843461"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="fromXDelta"
  type="int"
  transient="false"
@@ -7247,6 +7302,17 @@
  visibility="public"
 >
 </field>
+<field name="selection"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843455"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="settingsActivity"
  type="int"
  transient="false"
@@ -7434,6 +7500,17 @@
  visibility="public"
 >
 </field>
+<field name="sortOrder"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843456"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="soundEffectsEnabled"
  type="int"
  transient="false"
@@ -8622,6 +8699,17 @@
  visibility="public"
 >
 </field>
+<field name="to"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843459"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="toAlpha"
  type="int"
  transient="false"
@@ -8644,6 +8732,17 @@
  visibility="public"
 >
 </field>
+<field name="toValue"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843462"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="toXDelta"
  type="int"
  transient="false"
@@ -8820,6 +8919,17 @@
  visibility="public"
 >
 </field>
+<field name="uri"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843457"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="useLevel"
  type="int"
  transient="false"
@@ -9370,6 +9480,28 @@
  visibility="public"
 >
 </field>
+<field name="withClass"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843465"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="withExpression"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843464"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="writePermission"
  type="int"
  transient="false"
@@ -34644,6 +34776,17 @@
  visibility="public"
 >
 </field>
+<field name="STORAGE_SERVICE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;storage&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TELEPHONY_SERVICE"
  type="java.lang.String"
  transient="false"
@@ -120588,6 +120731,240 @@
 </method>
 </class>
 </package>
+<package name="android.os.storage"
+>
+<class name="StorageEventListener"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="StorageEventListener"
+ type="android.os.storage.StorageEventListener"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="onStorageStateChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+<parameter name="oldState" type="java.lang.String">
+</parameter>
+<parameter name="newState" type="java.lang.String">
+</parameter>
+</method>
+<method name="onUsbMassStorageConnectionChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="connected" type="boolean">
+</parameter>
+</method>
+</class>
+<class name="StorageManager"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="disableUsbMassStorage"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="enableUsbMassStorage"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isUsbMassStorageConnected"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isUsbMassStorageEnabled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="registerListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.os.storage.StorageEventListener">
+</parameter>
+</method>
+<method name="unregisterListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.os.storage.StorageEventListener">
+</parameter>
+</method>
+</class>
+<class name="StorageResultCode"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="StorageResultCode"
+ type="android.os.storage.StorageResultCode"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="OperationFailedInternalError"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OperationFailedMediaBlank"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OperationFailedMediaCorrupt"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OperationFailedNoMedia"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OperationFailedStorageBusy"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OperationFailedStorageMounted"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OperationFailedStorageNotMounted"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OperationSucceeded"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
 <package name="android.preference"
 >
 <class name="CheckBoxPreference"
@@ -197512,6 +197889,195 @@
 </parameter>
 </method>
 </interface>
+<class name="Adapters"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Adapters"
+ type="android.widget.Adapters"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="loadAdapter"
+ return="android.widget.BaseAdapter"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="id" type="int">
+</parameter>
+<parameter name="parameters" type="java.lang.Object...">
+</parameter>
+</method>
+<method name="loadCursorAdapter"
+ return="android.widget.CursorAdapter"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="id" type="int">
+</parameter>
+<parameter name="uri" type="java.lang.String">
+</parameter>
+<parameter name="parameters" type="java.lang.Object...">
+</parameter>
+</method>
+<method name="loadCursorAdapter"
+ return="android.widget.CursorAdapter"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="id" type="int">
+</parameter>
+<parameter name="cursor" type="android.database.Cursor">
+</parameter>
+<parameter name="parameters" type="java.lang.Object...">
+</parameter>
+</method>
+</class>
+<class name="Adapters.CursorBinder"
+ extends="java.lang.Object"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Adapters.CursorBinder"
+ type="android.widget.Adapters.CursorBinder"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="transformation" type="android.widget.Adapters.CursorTransformation">
+</parameter>
+</constructor>
+<method name="bind"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+<parameter name="cursor" type="android.database.Cursor">
+</parameter>
+<parameter name="columnIndex" type="int">
+</parameter>
+</method>
+<field name="mContext"
+ type="android.content.Context"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+<field name="mTransformation"
+ type="android.widget.Adapters.CursorTransformation"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<class name="Adapters.CursorTransformation"
+ extends="java.lang.Object"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Adapters.CursorTransformation"
+ type="android.widget.Adapters.CursorTransformation"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</constructor>
+<method name="transform"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cursor" type="android.database.Cursor">
+</parameter>
+<parameter name="columnIndex" type="int">
+</parameter>
+</method>
+<method name="transformToResource"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cursor" type="android.database.Cursor">
+</parameter>
+<parameter name="columnIndex" type="int">
+</parameter>
+</method>
+<field name="mContext"
+ type="android.content.Context"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
 <class name="AlphabetIndexer"
  extends="android.database.DataSetObserver"
  abstract="false"
@@ -199473,6 +200039,20 @@
 <parameter name="autoRequery" type="boolean">
 </parameter>
 </constructor>
+<constructor name="CursorAdapter"
+ type="android.widget.CursorAdapter"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="c" type="android.database.Cursor">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</constructor>
 <method name="bindView"
  return="void"
  abstract="true"
@@ -199620,6 +200200,23 @@
 <parameter name="autoRequery" type="boolean">
 </parameter>
 </method>
+<method name="init"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="c" type="android.database.Cursor">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
 <method name="newDropDownView"
  return="android.view.View"
  abstract="false"
@@ -199691,6 +200288,28 @@
 <parameter name="filterQueryProvider" type="android.widget.FilterQueryProvider">
 </parameter>
 </method>
+<field name="FLAG_AUTO_REQUERY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FLAG_REGISTER_CONTENT_OBSERVER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="CursorTreeAdapter"
  extends="android.widget.BaseExpandableListAdapter"
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ee87290..3c25635 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1373,7 +1373,6 @@
     public static final String SENSOR_SERVICE = "sensor";
     
     /**
-     * @hide
      * Use with {@link #getSystemService} to retrieve a {@link
      * android.os.storage.StorageManager} for accesssing system storage
      * functions.
diff --git a/core/java/android/os/storage/StorageEventListener.java b/core/java/android/os/storage/StorageEventListener.java
index 7b883a7..d3d39d6d 100644
--- a/core/java/android/os/storage/StorageEventListener.java
+++ b/core/java/android/os/storage/StorageEventListener.java
@@ -18,7 +18,6 @@
 
 /**
  * Used for receiving notifications from the StorageManager
- * @hide
  */
 public abstract class StorageEventListener {
     /**
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index a12603c..b49979c 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -45,8 +45,6 @@
  * {@link android.content.Context#getSystemService(java.lang.String)} with an argument
  * of {@link android.content.Context#STORAGE_SERVICE}.
  *
- * @hide
- *
  */
 
 public class StorageManager
diff --git a/core/java/android/os/storage/StorageResultCode.java b/core/java/android/os/storage/StorageResultCode.java
index 075f47f..07d95df 100644
--- a/core/java/android/os/storage/StorageResultCode.java
+++ b/core/java/android/os/storage/StorageResultCode.java
@@ -19,8 +19,6 @@
 /**
  * Class that provides access to constants returned from StorageManager
  * and lower level MountService APIs.
- *
- * @hide
  */
 public class StorageResultCode
 {
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 726793d..4686978 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -23,7 +23,10 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.text.TextUtils;
 import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
 
 /**
  * Shows a hierarchy of {@link Preference} objects as
@@ -69,30 +72,43 @@
  * As a convenience, this activity implements a click listener for any
  * preference in the current hierarchy, see
  * {@link #onPreferenceTreeClick(PreferenceScreen, Preference)}.
- * 
+ *
  * @see Preference
  * @see PreferenceScreen
  */
 public abstract class PreferenceActivity extends ListActivity implements
         PreferenceManager.OnPreferenceTreeClickListener {
-    
+
     private static final String PREFERENCES_TAG = "android:preferences";
-    
+
+    // extras that allow any preference activity to be launched as part of a wizard
+
+    // show Back and Next buttons? takes boolean parameter
+    // Back will then return RESULT_CANCELED and Next RESULT_OK
+    private static final String EXTRA_PREFS_SHOW_BUTTON_BAR = "extra_prefs_show_button_bar";
+
+    // specify custom text for the Back or Next buttons, or cause a button to not appear
+    // at all by setting it to null
+    private static final String EXTRA_PREFS_SET_NEXT_TEXT = "extra_prefs_set_next_text";
+    private static final String EXTRA_PREFS_SET_BACK_TEXT = "extra_prefs_set_back_text";
+
+    private Button mNextButton;
+
     private PreferenceManager mPreferenceManager;
-    
+
     private Bundle mSavedInstanceState;
 
     /**
      * The starting request code given out to preference framework.
      */
     private static final int FIRST_REQUEST_CODE = 100;
-    
+
     private static final int MSG_BIND_PREFERENCES = 0;
     private Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-                
+
                 case MSG_BIND_PREFERENCES:
                     bindPreferences();
                     break;
@@ -105,7 +121,49 @@
         super.onCreate(savedInstanceState);
 
         setContentView(com.android.internal.R.layout.preference_list_content);
-        
+
+        // see if we should show Back/Next buttons
+        Intent intent = getIntent();
+        if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false)) {
+
+            findViewById(com.android.internal.R.id.button_bar).setVisibility(View.VISIBLE);
+
+            Button backButton = (Button)findViewById(com.android.internal.R.id.back_button);
+            backButton.setOnClickListener(new OnClickListener() {
+                public void onClick(View v) {
+                    setResult(RESULT_CANCELED);
+                    finish();
+                }
+            });
+            mNextButton = (Button)findViewById(com.android.internal.R.id.next_button);
+            mNextButton.setOnClickListener(new OnClickListener() {
+                public void onClick(View v) {
+                    setResult(RESULT_OK);
+                    finish();
+                }
+            });
+
+            // set our various button parameters
+            if (intent.hasExtra(EXTRA_PREFS_SET_NEXT_TEXT)) {
+                String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_NEXT_TEXT);
+                if (TextUtils.isEmpty(buttonText)) {
+                    mNextButton.setVisibility(View.GONE);
+                }
+                else {
+                    mNextButton.setText(buttonText);
+                }
+            }
+            if (intent.hasExtra(EXTRA_PREFS_SET_BACK_TEXT)) {
+                String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_BACK_TEXT);
+                if (TextUtils.isEmpty(buttonText)) {
+                    backButton.setVisibility(View.GONE);
+                }
+                else {
+                    backButton.setText(buttonText);
+                }
+            }
+        }
+
         mPreferenceManager = onCreatePreferenceManager();
         getListView().setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
     }
@@ -113,14 +171,13 @@
     @Override
     protected void onStop() {
         super.onStop();
-        
+
         mPreferenceManager.dispatchActivityStop();
     }
 
     @Override
     protected void onDestroy() {
         super.onDestroy();
-        
         mPreferenceManager.dispatchActivityDestroy();
     }
 
@@ -156,7 +213,7 @@
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
-        
+
         mPreferenceManager.dispatchActivityResult(requestCode, resultCode, data);
     }
 
@@ -176,7 +233,7 @@
         if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) return;
         mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
     }
-    
+
     private void bindPreferences() {
         final PreferenceScreen preferenceScreen = getPreferenceScreen();
         if (preferenceScreen != null) {
@@ -187,10 +244,10 @@
             }
         }
     }
-    
+
     /**
      * Creates the {@link PreferenceManager}.
-     * 
+     *
      * @return The {@link PreferenceManager} used by this activity.
      */
     private PreferenceManager onCreatePreferenceManager() {
@@ -198,7 +255,7 @@
         preferenceManager.setOnPreferenceTreeClickListener(this);
         return preferenceManager;
     }
-    
+
     /**
      * Returns the {@link PreferenceManager} used by this activity.
      * @return The {@link PreferenceManager}.
@@ -206,7 +263,7 @@
     public PreferenceManager getPreferenceManager() {
         return mPreferenceManager;
     }
-    
+
     private void requirePreferenceManager() {
         if (mPreferenceManager == null) {
             throw new RuntimeException("This should be called after super.onCreate.");
@@ -215,7 +272,7 @@
 
     /**
      * Sets the root of the preference hierarchy that this activity is showing.
-     * 
+     *
      * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
      */
     public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
@@ -228,37 +285,37 @@
             }
         }
     }
-    
+
     /**
      * Gets the root of the preference hierarchy that this activity is showing.
-     * 
+     *
      * @return The {@link PreferenceScreen} that is the root of the preference
      *         hierarchy.
      */
     public PreferenceScreen getPreferenceScreen() {
         return mPreferenceManager.getPreferenceScreen();
     }
-    
+
     /**
      * Adds preferences from activities that match the given {@link Intent}.
-     * 
+     *
      * @param intent The {@link Intent} to query activities.
      */
     public void addPreferencesFromIntent(Intent intent) {
         requirePreferenceManager();
-        
+
         setPreferenceScreen(mPreferenceManager.inflateFromIntent(intent, getPreferenceScreen()));
     }
-    
+
     /**
      * Inflates the given XML resource and adds the preference hierarchy to the current
      * preference hierarchy.
-     * 
+     *
      * @param preferencesResId The XML resource ID to inflate.
      */
     public void addPreferencesFromResource(int preferencesResId) {
         requirePreferenceManager();
-        
+
         setPreferenceScreen(mPreferenceManager.inflateFromResource(this, preferencesResId,
                 getPreferenceScreen()));
     }
@@ -269,20 +326,20 @@
     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
         return false;
     }
-    
+
     /**
      * Finds a {@link Preference} based on its key.
-     * 
+     *
      * @param key The key of the preference to retrieve.
      * @return The {@link Preference} with the key, or null.
      * @see PreferenceGroup#findPreference(CharSequence)
      */
     public Preference findPreference(CharSequence key) {
-        
+
         if (mPreferenceManager == null) {
             return null;
         }
-        
+
         return mPreferenceManager.findPreference(key);
     }
 
@@ -292,5 +349,14 @@
             mPreferenceManager.dispatchNewIntent(intent);
         }
     }
-    
+
+    // give subclasses access to the Next button
+    /** @hide */
+    protected boolean hasNextButton() {
+        return mNextButton != null;
+    }
+    /** @hide */
+    protected Button getNextButton() {
+        return mNextButton;
+    }
 }
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 14e5655..b6aa03a 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -310,7 +310,6 @@
 
         Directions[] objects = new Directions[1];
 
-
         for (int i = 0; i < n; i++) {
             ints[START] = reflowed.getLineStart(i) |
                           (reflowed.getParagraphDirection(i) << DIR_SHIFT) |
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 38ac9b7..ff1f2a60 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -16,25 +16,31 @@
 
 package android.text;
 
+import com.android.internal.util.ArrayUtils;
+
 import android.emoji.EmojiFactory;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Paint;
+import android.graphics.Path;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.graphics.Path;
-import com.android.internal.util.ArrayUtils;
-
-import junit.framework.Assert;
-import android.text.style.*;
 import android.text.method.TextKeyListener;
+import android.text.style.AlignmentSpan;
+import android.text.style.LeadingMarginSpan;
+import android.text.style.LineBackgroundSpan;
+import android.text.style.ParagraphStyle;
+import android.text.style.ReplacementSpan;
+import android.text.style.TabStopSpan;
 import android.view.KeyEvent;
 
+import junit.framework.Assert;
+
 /**
- * A base class that manages text layout in visual elements on 
- * the screen. 
- * <p>For text that will be edited, use a {@link DynamicLayout}, 
- * which will be updated as the text changes.  
+ * A base class that manages text layout in visual elements on
+ * the screen.
+ * <p>For text that will be edited, use a {@link DynamicLayout},
+ * which will be updated as the text changes.
  * For text that will not change, use a {@link StaticLayout}.
  */
 public abstract class Layout {
@@ -66,7 +72,7 @@
                                         TextPaint paint) {
         return getDesiredWidth(source, 0, source.length(), paint);
     }
-    
+
     /**
      * Return how wide a layout must be in order to display the
      * specified text slice with one line per paragraph.
@@ -185,13 +191,13 @@
         if (dbottom < bottom) {
             bottom = dbottom;
         }
-        
-        int first = getLineForVertical(top); 
+
+        int first = getLineForVertical(top);
         int last = getLineForVertical(bottom);
-        
+
         int previousLineBottom = getLineTop(first);
         int previousLineEnd = getLineStart(first);
-        
+
         TextPaint paint = mPaint;
         CharSequence buf = mText;
         int width = mWidth;
@@ -238,7 +244,7 @@
             previousLineBottom = getLineTop(first);
             previousLineEnd = getLineStart(first);
             spans = NO_PARA_SPANS;
-        } 
+        }
 
         // There can be a highlight even without spans if we are drawing
         // a non-spanned transformation of a spanned editing buffer.
@@ -255,7 +261,7 @@
         }
 
         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.
@@ -271,7 +277,7 @@
             int lbaseline = lbottom - getLineDescent(i);
 
             boolean isFirstParaLine = false;
-            if (spannedText) { 
+            if (spannedText) {
                 if (start == 0 || buf.charAt(start - 1) == '\n') {
                     isFirstParaLine = true;
                 }
@@ -282,7 +288,7 @@
                     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) {
@@ -292,7 +298,7 @@
                     }
                 }
             }
-            
+
             int dir = getParagraphDirection(i);
             int left = 0;
             int right = mWidth;
@@ -309,7 +315,7 @@
                             margin.drawLeadingMargin(c, paint, right, dir, ltop,
                                                      lbaseline, lbottom, buf,
                                                      start, end, isFirstParaLine, this);
-                                
+
                             right -= margin.getLeadingMargin(isFirstParaLine);
                         } else {
                             margin.drawLeadingMargin(c, paint, left, dir, ltop,
@@ -417,7 +423,7 @@
 
         mWidth = wid;
     }
-    
+
     /**
      * Return the total height of this layout.
      */
@@ -450,7 +456,7 @@
      * Return the number of lines of text in this layout.
      */
     public abstract int getLineCount();
-    
+
     /**
      * Return the baseline for the specified line (0&hellip;getLineCount() - 1)
      * If bounds is not null, return the top, left, right, bottom extents
@@ -524,13 +530,95 @@
      */
     public abstract int getBottomPadding();
 
+
+    /**
+     * Returns true if the character at offset and the preceding character
+     * are at different run levels (and thus there's a split caret).
+     * @param offset the offset
+     * @return true if at a level boundary
+     */
+    private boolean isLevelBoundary(int offset) {
+        int line = getLineForOffset(offset);
+        Directions dirs = getLineDirections(line);
+        if (dirs == DIRS_ALL_LEFT_TO_RIGHT || dirs == DIRS_ALL_RIGHT_TO_LEFT) {
+            return false;
+        }
+
+        int[] runs = dirs.mDirections;
+        int lineStart = getLineStart(line);
+        int lineEnd = getLineEnd(line);
+        if (offset == lineStart || offset == lineEnd) {
+            int paraLevel = getParagraphDirection(line) == 1 ? 0 : 1;
+            int runIndex = offset == lineStart ? 0 : runs.length - 2;
+            return ((runs[runIndex + 1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK) != paraLevel;
+        }
+
+        offset -= lineStart;
+        for (int i = 0; i < runs.length; i += 2) {
+            if (offset == runs[i]) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean primaryIsTrailingPrevious(int offset) {
+        int line = getLineForOffset(offset);
+        int lineStart = getLineStart(line);
+        int lineEnd = getLineEnd(line);
+        int[] runs = getLineDirections(line).mDirections;
+
+        int levelAt = -1;
+        for (int i = 0; i < runs.length; i += 2) {
+            int start = lineStart + runs[i];
+            int limit = start + (runs[i+1] & RUN_LENGTH_MASK);
+            if (limit > lineEnd) {
+                limit = lineEnd;
+            }
+            if (offset >= start && offset < limit) {
+                if (offset > start) {
+                    // Previous character is at same level, so don't use trailing.
+                    return false;
+                }
+                levelAt = (runs[i+1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK;
+                break;
+            }
+        }
+        if (levelAt == -1) {
+            // Offset was limit of line.
+            levelAt = getParagraphDirection(line) == 1 ? 0 : 1;
+        }
+
+        // At level boundary, check previous level.
+        int levelBefore = -1;
+        if (offset == lineStart) {
+            levelBefore = getParagraphDirection(line) == 1 ? 0 : 1;
+        } else {
+            offset -= 1;
+            for (int i = 0; i < runs.length; i += 2) {
+                int start = lineStart + runs[i];
+                int limit = start + (runs[i+1] & RUN_LENGTH_MASK);
+                if (limit > lineEnd) {
+                    limit = lineEnd;
+                }
+                if (offset >= start && offset < limit) {
+                    levelBefore = (runs[i+1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK;
+                    break;
+                }
+            }
+        }
+
+        return levelBefore < levelAt;
+    }
+
     /**
      * Get the primary horizontal position for the specified text offset.
      * This is the location where a new character would be inserted in
      * the paragraph's primary direction.
      */
     public float getPrimaryHorizontal(int offset) {
-        return getHorizontal(offset, false, true);
+        boolean trailing = primaryIsTrailingPrevious(offset);
+        return getHorizontal(offset, trailing);
     }
 
     /**
@@ -539,17 +627,17 @@
      * the direction other than the paragraph's primary direction.
      */
     public float getSecondaryHorizontal(int offset) {
-        return getHorizontal(offset, true, true);
+        boolean trailing = primaryIsTrailingPrevious(offset);
+        return getHorizontal(offset, !trailing);
     }
 
-    private float getHorizontal(int offset, boolean trailing, boolean alt) {
+    private float getHorizontal(int offset, boolean trailing) {
         int line = getLineForOffset(offset);
 
-        return getHorizontal(offset, trailing, alt, line);
+        return getHorizontal(offset, trailing, line);
     }
 
-    private float getHorizontal(int offset, boolean trailing, boolean alt,
-                                int line) {
+    private float getHorizontal(int offset, boolean trailing, int line) {
         int start = getLineStart(line);
         int end = getLineVisibleEnd(line);
         int dir = getParagraphDirection(line);
@@ -562,7 +650,7 @@
         }
 
         float wid = measureText(mPaint, mWorkPaint, mText, start, offset, end,
-                                dir, directions, trailing, alt, tab, tabs);
+                                dir, directions, trailing, tab, tabs);
 
         if (offset > end) {
             if (dir == DIR_RIGHT_TO_LEFT)
@@ -679,7 +767,7 @@
             end = getLineEnd(line);
         } else {
             end = getLineVisibleEnd(line);
-        } 
+        }
         boolean tab = getLineContainsTab(line);
 
         if (tabs == null && tab && mText instanceof Spanned) {
@@ -738,7 +826,7 @@
     }
 
     /**
-     * Get the character offset on the specfied line whose position is
+     * Get the character offset on the specified line whose position is
      * closest to the specified horizontal position.
      */
     public int getOffsetForHorizontal(int line, float horiz) {
@@ -752,14 +840,13 @@
         int best = min;
         float bestdist = Math.abs(getPrimaryHorizontal(best) - horiz);
 
-        int here = min;
-        for (int i = 0; i < dirs.mDirections.length; i++) {
-            int there = here + dirs.mDirections[i];
-            int swap = ((i & 1) == 0) ? 1 : -1;
+        for (int i = 0; i < dirs.mDirections.length; i += 2) {
+            int here = min + dirs.mDirections[i];
+            int there = here + (dirs.mDirections[i+1] & RUN_LENGTH_MASK);
+            int swap = (dirs.mDirections[i+1] & RUN_RTL_FLAG) != 0 ? -1 : 1;
 
             if (there > max)
                 there = max;
-
             int high = there - 1 + 1, low = here + 1 - 1, guess;
 
             while (high - low > 1) {
@@ -792,7 +879,7 @@
 
                 if (dist < bestdist) {
                     bestdist = dist;
-                    best = low;   
+                    best = low;
                 }
             }
 
@@ -802,8 +889,6 @@
                 bestdist = dist;
                 best = here;
             }
-
-            here = there;
         }
 
         float dist = Math.abs(getPrimaryHorizontal(max) - horiz);
@@ -823,14 +908,14 @@
         return getLineStart(line + 1);
     }
 
-    /** 
+    /**
      * Return the text offset after the last visible character (so whitespace
      * is not counted) on the specified line.
      */
     public int getLineVisibleEnd(int line) {
         return getLineVisibleEnd(line, getLineStart(line), getLineStart(line+1));
     }
-    
+
     private int getLineVisibleEnd(int line, int start, int end) {
         if (DEBUG) {
             Assert.assertTrue(getLineStart(line) == start && getLineStart(line+1) == end);
@@ -882,207 +967,178 @@
         return getLineTop(line) - (getLineTop(line+1) - getLineDescent(line));
     }
 
-    /**
-     * Return the text offset that would be reached by moving left
-     * (possibly onto another line) from the specified offset.
-     */
     public int getOffsetToLeftOf(int offset) {
-        int line = getLineForOffset(offset);
-        int start = getLineStart(line);
-        int end = getLineEnd(line);
-        Directions dirs = getLineDirections(line);
-
-        if (line != getLineCount() - 1)
-            end--;
-
-        float horiz = getPrimaryHorizontal(offset);
-
-        int best = offset;
-        float besth = Integer.MIN_VALUE;
-        int candidate;
-
-        candidate = TextUtils.getOffsetBefore(mText, offset);
-        if (candidate >= start && candidate <= end) {
-            float h = getPrimaryHorizontal(candidate);
-
-            if (h < horiz && h > besth) {
-                best = candidate;
-                besth = h;
-            }
-        }
-
-        candidate = TextUtils.getOffsetAfter(mText, offset);
-        if (candidate >= start && candidate <= end) {
-            float h = getPrimaryHorizontal(candidate);
-
-            if (h < horiz && h > besth) {
-                best = candidate;
-                besth = h;
-            }
-        }
-
-        int here = start;
-        for (int i = 0; i < dirs.mDirections.length; i++) {
-            int there = here + dirs.mDirections[i];
-            if (there > end)
-                there = end;
-
-            float h = getPrimaryHorizontal(here);
-
-            if (h < horiz && h > besth) {
-                best = here;
-                besth = h;
-            }
-
-            candidate = TextUtils.getOffsetAfter(mText, here);
-            if (candidate >= start && candidate <= end) {
-                h = getPrimaryHorizontal(candidate);
-
-                if (h < horiz && h > besth) {
-                    best = candidate;
-                    besth = h;
-                }
-            }
-
-            candidate = TextUtils.getOffsetBefore(mText, there);
-            if (candidate >= start && candidate <= end) {
-                h = getPrimaryHorizontal(candidate);
-
-                if (h < horiz && h > besth) {
-                    best = candidate;
-                    besth = h;
-                }
-            }
-
-            here = there;
-        }
-
-        float h = getPrimaryHorizontal(end);
-
-        if (h < horiz && h > besth) {
-            best = end;
-            besth = h;
-        }
-
-        if (best != offset)
-            return best;
-
-        int dir = getParagraphDirection(line);
-
-        if (dir > 0) {
-            if (line == 0)
-                return best;
-            else
-                return getOffsetForHorizontal(line - 1, 10000);
-        } else {
-            if (line == getLineCount() - 1)
-                return best;
-            else
-                return getOffsetForHorizontal(line + 1, 10000);
-        }
+        return getOffsetToLeftRightOf(offset, true);
     }
 
-    /**
-     * Return the text offset that would be reached by moving right
-     * (possibly onto another line) from the specified offset.
-     */
     public int getOffsetToRightOf(int offset) {
-        int line = getLineForOffset(offset);
-        int start = getLineStart(line);
-        int end = getLineEnd(line);
-        Directions dirs = getLineDirections(line);
+        return getOffsetToLeftRightOf(offset, false);
+    }
 
-        if (line != getLineCount() - 1)
-            end--;
+    // 1) The caret marks the leading edge of a character. The character
+    // logically before it might be on a different level, and the active caret
+    // position is on the character at the lower level. If that character
+    // was the previous character, the caret is on its trailing edge.
+    // 2) Take this character/edge and move it in the indicated direction.
+    // This gives you a new character and a new edge.
+    // 3) This position is between two visually adjacent characters.  One of
+    // these might be at a lower level.  The active position is on the
+    // character at the lower level.
+    // 4) If the active position is on the trailing edge of the character,
+    // the new caret position is the following logical character, else it
+    // is the character.
+    private int getOffsetToLeftRightOf(int caret, boolean toLeft) {
+        int line = getLineForOffset(caret);
+        int lineStart = getLineStart(line);
+        int lineEnd = getLineEnd(line);
 
-        float horiz = getPrimaryHorizontal(offset);
+        boolean paraIsRtl = getParagraphDirection(line) == -1;
+        int[] runs = getLineDirections(line).mDirections;
 
-        int best = offset;
-        float besth = Integer.MAX_VALUE;
-        int candidate;
+        int runIndex, runLevel = 0, runStart = lineStart, runLimit = lineEnd, newCaret = -1;
+        boolean trailing = false;
 
-        candidate = TextUtils.getOffsetBefore(mText, offset);
-        if (candidate >= start && candidate <= end) {
-            float h = getPrimaryHorizontal(candidate);
-
-            if (h > horiz && h < besth) {
-                best = candidate;
-                besth = h;
-            }
-        }
-
-        candidate = TextUtils.getOffsetAfter(mText, offset);
-        if (candidate >= start && candidate <= end) {
-            float h = getPrimaryHorizontal(candidate);
-
-            if (h > horiz && h < besth) {
-                best = candidate;
-                besth = h;
-            }
-        }
-
-        int here = start;
-        for (int i = 0; i < dirs.mDirections.length; i++) {
-            int there = here + dirs.mDirections[i];
-            if (there > end)
-                there = end;
-
-            float h = getPrimaryHorizontal(here);
-
-            if (h > horiz && h < besth) {
-                best = here;
-                besth = h;
-            }
-
-            candidate = TextUtils.getOffsetAfter(mText, here);
-            if (candidate >= start && candidate <= end) {
-                h = getPrimaryHorizontal(candidate);
-
-                if (h > horiz && h < besth) {
-                    best = candidate;
-                    besth = h;
-                }
-            }
-
-            candidate = TextUtils.getOffsetBefore(mText, there);
-            if (candidate >= start && candidate <= end) {
-                h = getPrimaryHorizontal(candidate);
-
-                if (h > horiz && h < besth) {
-                    best = candidate;
-                    besth = h;
-                }
-            }
-
-            here = there;
-        }
-
-        float h = getPrimaryHorizontal(end);
-
-        if (h > horiz && h < besth) {
-            best = end;
-            besth = h;
-        }
-
-        if (best != offset)
-            return best;
-
-        int dir = getParagraphDirection(line);
-
-        if (dir > 0) {
-            if (line == getLineCount() - 1)
-                return best;
-            else
-                return getOffsetForHorizontal(line + 1, -10000);
+        if (caret == lineStart) {
+            runIndex = -2;
+        } else if (caret == lineEnd) {
+            runIndex = runs.length;
         } else {
-            if (line == 0)
-                return best;
-            else
-                return getOffsetForHorizontal(line - 1, -10000);
+          // First, get information about the run containing the character with
+          // the active caret.
+          for (runIndex = 0; runIndex < runs.length; runIndex += 2) {
+            runStart = lineStart + runs[runIndex];
+            if (caret >= runStart) {
+              runLimit = runStart + (runs[runIndex+1] & RUN_LENGTH_MASK);
+              if (runLimit > lineEnd) {
+                  runLimit = lineEnd;
+              }
+              if (caret < runLimit) {
+                runLevel = (runs[runIndex+1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK;
+                if (caret == runStart) {
+                  // The caret is on a run boundary, see if we should
+                  // use the position on the trailing edge of the previous
+                  // logical character instead.
+                  int prevRunIndex, prevRunLevel, prevRunStart, prevRunLimit;
+                  int pos = caret - 1;
+                  for (prevRunIndex = 0; prevRunIndex < runs.length; prevRunIndex += 2) {
+                    prevRunStart = lineStart + runs[prevRunIndex];
+                    if (pos >= prevRunStart) {
+                      prevRunLimit = prevRunStart + (runs[prevRunIndex+1] & RUN_LENGTH_MASK);
+                      if (prevRunLimit > lineEnd) {
+                          prevRunLimit = lineEnd;
+                      }
+                      if (pos < prevRunLimit) {
+                        prevRunLevel = (runs[prevRunIndex+1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK;
+                        if (prevRunLevel < runLevel) {
+                          // Start from logically previous character.
+                          runIndex = prevRunIndex;
+                          runLevel = prevRunLevel;
+                          runStart = prevRunStart;
+                          runLimit = prevRunLimit;
+                          trailing = true;
+                          break;
+                        }
+                      }
+                    }
+                  }
+                }
+                break;
+              }
+            }
+          }
+
+          // caret might be = lineEnd.  This is generally a space or paragraph
+          // separator and has an associated run, but might be the end of
+          // text, in which case it doesn't.  If that happens, we ran off the
+          // end of the run list, and runIndex == runs.length.  In this case,
+          // we are at a run boundary so we skip the below test.
+          if (runIndex != runs.length) {
+              boolean rtlRun = (runLevel & 0x1) != 0;
+              boolean advance = toLeft == rtlRun;
+              if (caret != (advance ? runLimit : runStart) || advance != trailing) {
+                  // Moving within or into the run, so we can move logically.
+                  newCaret = getOffsetBeforeAfter(caret, advance);
+                  // If the new position is internal to the run, we're at the strong
+                  // position already so we're finished.
+                  if (newCaret != (advance ? runLimit : runStart)) {
+                      return newCaret;
+                  }
+              }
+          }
         }
+
+        // If newCaret is -1, we're starting at a run boundary and crossing
+        // into another run. Otherwise we've arrived at a run boundary, and
+        // need to figure out which character to attach to.  Note we might
+        // need to run this twice, if we cross a run boundary and end up at
+        // another run boundary.
+        while (true) {
+          boolean advance = toLeft == paraIsRtl;
+          int otherRunIndex = runIndex + (advance ? 2 : -2);
+          if (otherRunIndex >= 0 && otherRunIndex < runs.length) {
+            int otherRunStart = lineStart + runs[otherRunIndex];
+            int otherRunLimit = otherRunStart + (runs[otherRunIndex+1] & RUN_LENGTH_MASK);
+            if (otherRunLimit > lineEnd) {
+                otherRunLimit = lineEnd;
+            }
+            int otherRunLevel = runs[otherRunIndex+1] >>> RUN_LEVEL_SHIFT & RUN_LEVEL_MASK;
+            boolean otherRunIsRtl = (otherRunLevel & 1) != 0;
+
+            advance = toLeft == otherRunIsRtl;
+            if (newCaret == -1) {
+              newCaret = getOffsetBeforeAfter(advance ? otherRunStart : otherRunLimit, advance);
+              if (newCaret == (advance ? otherRunLimit : otherRunStart)) {
+                // Crossed and ended up at a new boundary, repeat a second and final time.
+                runIndex = otherRunIndex;
+                runLevel = otherRunLevel;
+                continue;
+              }
+              break;
+            }
+
+            // The new caret is at a boundary.
+            if (otherRunLevel < runLevel) {
+              // The strong character is in the other run.
+              newCaret = advance ? otherRunStart : otherRunLimit;
+            }
+            break;
+          }
+
+          if (newCaret == -1) {
+              // We're walking off the end of the line.  The paragraph
+              // level is always equal to or lower than any internal level, so
+              // the boundaries get the strong caret.
+              newCaret = getOffsetBeforeAfter(caret, advance);
+              break;
+          }
+          // Else we've arrived at the end of the line.  That's a strong position.
+          // We might have arrived here by crossing over a run with no internal
+          // breaks and dropping out of the above loop before advancing one final
+          // time, so reset the caret.
+          // Note, we use '<=' below to handle a situation where the only run
+          // on the line is a counter-directional run.  If we're not advancing,
+          // we can end up at the 'lineEnd' position but the caret we want is at
+          // the lineStart.
+          if (newCaret <= lineEnd) {
+              newCaret = advance ? lineEnd : lineStart;
+          }
+          break;
+        }
+
+        return newCaret;
+    }
+
+    // utility, maybe just roll into the above.
+    private int getOffsetBeforeAfter(int offset, boolean after) {
+        if (after) {
+            return TextUtils.getOffsetAfter(mText, offset);
+        }
+        return TextUtils.getOffsetBefore(mText, offset);
     }
 
     private int getOffsetAtStartOf(int offset) {
+        // XXX this probably should skip local reorderings and
+        // zero-width characters, look at callers
         if (offset == 0)
             return 0;
 
@@ -1115,7 +1171,7 @@
     /**
      * Fills in the specified Path with a representation of a cursor
      * at the specified offset.  This will often be a vertical line
-     * but can be multiple discontinous lines in text with multiple
+     * but can be multiple discontinuous lines in text with multiple
      * directionalities.
      */
     public void getCursorPath(int point, Path dest,
@@ -1127,7 +1183,8 @@
         int bottom = getLineTop(line+1);
 
         float h1 = getPrimaryHorizontal(point) - 0.5f;
-        float h2 = getSecondaryHorizontal(point) - 0.5f;
+        float h2 = isLevelBoundary(point) ?
+                    getSecondaryHorizontal(point) - 0.5f : h1;
 
         int caps = TextKeyListener.getMetaState(editingBuffer,
                                                 KeyEvent.META_SHIFT_ON) |
@@ -1204,9 +1261,10 @@
         if (lineend > linestart && mText.charAt(lineend - 1) == '\n')
             lineend--;
 
-        int here = linestart;
-        for (int i = 0; i < dirs.mDirections.length; i++) {
-            int there = here + dirs.mDirections[i];
+        for (int i = 0; i < dirs.mDirections.length; i += 2) {
+            int here = linestart + dirs.mDirections[i];
+            int there = here + (dirs.mDirections[i+1] & RUN_LENGTH_MASK);
+
             if (there > lineend)
                 there = lineend;
 
@@ -1215,14 +1273,12 @@
                 int en = Math.min(end, there);
 
                 if (st != en) {
-                    float h1 = getHorizontal(st, false, false, line);
-                    float h2 = getHorizontal(en, true, false, line);
+                    float h1 = getHorizontal(st, false, line);
+                    float h2 = getHorizontal(en, true, line);
 
                     dest.addRect(h1, top, h2, bottom, Path.Direction.CW);
                 }
             }
-
-            here = there;
         }
     }
 
@@ -1257,7 +1313,7 @@
 
             addSelection(startline, start, getLineEnd(startline),
                          top, getLineBottom(startline), dest);
-            
+
             if (getParagraphDirection(startline) == DIR_RIGHT_TO_LEFT)
                 dest.addRect(getLineLeft(startline), top,
                               0, getLineBottom(startline), Path.Direction.CW);
@@ -1395,27 +1451,31 @@
 
         float h = 0;
 
-        int here = 0;
-        for (int i = 0; i < directions.mDirections.length; i++) {
-            int there = here + directions.mDirections[i];
-            if (there > end - start)
-                there = end - start;
+        int lastRunIndex = directions.mDirections.length - 2;
+        for (int i = 0; i < directions.mDirections.length; i += 2) {
+            int here = start + directions.mDirections[i];
+            int there = here + (directions.mDirections[i+1] & RUN_LENGTH_MASK);
+            boolean runIsRtl = (directions.mDirections[i+1] & RUN_RTL_FLAG) != 0;
+
+            if (there > end)
+                there = end;
 
             int segstart = here;
             for (int j = hasTabs ? here : there; j <= there; j++) {
-                if (j == there || buf[j] == '\t') {
+                int pj = j - start;
+                if (j == there || buf[pj] == '\t') {
                     h += Styled.drawText(canvas, text,
-                                         start + segstart, start + j,
-                                         dir, (i & 1) != 0, x + h,
+                                         segstart, j,
+                                         dir, runIsRtl, x + h,
                                          top, y, bottom, paint, workPaint,
-                                         start + j != end);
+                                         i != lastRunIndex || j != end);
 
-                    if (j != there && buf[j] == '\t')
+                    if (j != there)
                         h = dir * nextTab(text, start, end, h * dir, parspans);
 
                     segstart = j + 1;
-                } else if (hasTabs && buf[j] >= 0xD800 && buf[j] <= 0xDFFF && j + 1 < there) {
-                    int emoji = Character.codePointAt(buf, j);
+                } else if (hasTabs && buf[pj] >= 0xD800 && buf[pj] <= 0xDFFF && j + 1 < there) {
+                    int emoji = Character.codePointAt(buf, pj);
 
                     if (emoji >= MIN_EMOJI && emoji <= MAX_EMOJI) {
                         Bitmap bm = EMOJI_FACTORY.
@@ -1423,10 +1483,10 @@
 
                         if (bm != null) {
                             h += Styled.drawText(canvas, text,
-                                                 start + segstart, start + j,
-                                                 dir, (i & 1) != 0, x + h,
+                                                 segstart, j,
+                                                 dir, runIsRtl, x + h,
                                                  top, y, bottom, paint, workPaint,
-                                                 start + j != end);
+                                                 i != lastRunIndex || j != end);
 
                             if (mEmojiRect == null) {
                                 mEmojiRect = new RectF();
@@ -1434,9 +1494,9 @@
 
                             workPaint.set(paint);
                             Styled.measureText(paint, workPaint, text,
-                                               start + j, start + j + 1,
+                                               j, j + 1,
                                                null);
-                                        
+
                             float bitmapHeight = bm.getHeight();
                             float textHeight = -workPaint.ascent();
                             float scale = textHeight / bitmapHeight;
@@ -1454,21 +1514,24 @@
                     }
                 }
             }
-
-            here = there;
         }
 
         if (hasTabs)
             TextUtils.recycle(buf);
     }
 
-    private static float measureText(TextPaint paint,
+    /**
+     * Get the distance from the margin to the requested edge of the character
+     * at offset on the line from start to end.  Trailing indicates the edge
+     * should be the trailing edge of the character at offset-1.
+     */
+    /* package */ static float measureText(TextPaint paint,
                                      TextPaint workPaint,
                                      CharSequence text,
                                      int start, int offset, int end,
                                      int dir, Directions directions,
-                                     boolean trailing, boolean alt,
-                                     boolean hasTabs, Object[] tabs) {
+                                     boolean trailing, boolean hasTabs,
+                                     Object[] tabs) {
         char[] buf = null;
 
         if (hasTabs) {
@@ -1478,19 +1541,19 @@
 
         float h = 0;
 
-        if (alt) {
-            if (dir == DIR_RIGHT_TO_LEFT)
-                trailing = !trailing;
+        int target = trailing ? offset - 1 : offset;
+        if (target < start) {
+            return 0;
         }
 
-        int here = 0;
-        for (int i = 0; i < directions.mDirections.length; i++) {
-            if (alt)
-                trailing = !trailing;
-
-            int there = here + directions.mDirections[i];
-            if (there > end - start)
-                there = end - start;
+        int[] runs = directions.mDirections;
+        for (int i = 0; i < runs.length; i += 2) {
+            int here = start + runs[i];
+            int there = here + (runs[i+1] & RUN_LENGTH_MASK);
+            if (there > end) {
+                there = end;
+            }
+            boolean runIsRtl = (runs[i+1] & RUN_RTL_FLAG) != 0;
 
             int segstart = here;
             for (int j = hasTabs ? here : there; j <= there; j++) {
@@ -1498,11 +1561,11 @@
                 Bitmap bm = null;
 
                 if (hasTabs && j < there) {
-                    codept = buf[j];
+                    codept = buf[j - start];
                 }
 
                 if (codept >= 0xD800 && codept <= 0xDFFF && j + 1 < there) {
-                    codept = Character.codePointAt(buf, j);
+                    codept = Character.codePointAt(buf, j - start);
 
                     if (codept >= MIN_EMOJI && codept <= MAX_EMOJI) {
                         bm = EMOJI_FACTORY.getBitmapFromAndroidPua(codept);
@@ -1512,33 +1575,34 @@
                 if (j == there || codept == '\t' || bm != null) {
                     float segw;
 
-                    if (offset < start + j ||
-                       (trailing && offset <= start + j)) {
-                        if (dir == DIR_LEFT_TO_RIGHT && (i & 1) == 0) {
+                    boolean inSegment = target >= segstart && target < j;
+
+                    if (inSegment) {
+                        if (dir == DIR_LEFT_TO_RIGHT && !runIsRtl) {
                             h += Styled.measureText(paint, workPaint, text,
-                                                    start + segstart, offset,
+                                                    segstart, offset,
                                                     null);
                             return h;
                         }
 
-                        if (dir == DIR_RIGHT_TO_LEFT && (i & 1) != 0) {
+                        if (dir == DIR_RIGHT_TO_LEFT && runIsRtl) {
                             h -= Styled.measureText(paint, workPaint, text,
-                                                    start + segstart, offset,
+                                                    segstart, offset,
                                                     null);
                             return h;
                         }
                     }
 
+                    // XXX Style.measureText assumes LTR?
                     segw = Styled.measureText(paint, workPaint, text,
-                                              start + segstart, start + j,
+                                              segstart, j,
                                               null);
 
-                    if (offset < start + j ||
-                        (trailing && offset <= start + j)) {
+                    if (inSegment) {
                         if (dir == DIR_LEFT_TO_RIGHT) {
                             h += segw - Styled.measureText(paint, workPaint,
                                                            text,
-                                                           start + segstart,
+                                                           segstart,
                                                            offset, null);
                             return h;
                         }
@@ -1546,7 +1610,7 @@
                         if (dir == DIR_RIGHT_TO_LEFT) {
                             h -= segw - Styled.measureText(paint, workPaint,
                                                            text,
-                                                           start + segstart,
+                                                           segstart,
                                                            offset, null);
                             return h;
                         }
@@ -1557,11 +1621,15 @@
                     else
                         h += segw;
 
-                    if (j != there && buf[j] == '\t') {
-                        if (offset == start + j)
+                    if (j != there && buf[j - start] == '\t') {
+                        if (offset == j)
                             return h;
 
                         h = dir * nextTab(text, start, end, h * dir, tabs);
+
+                        if (target == j) {
+                            return h;
+                        }
                     }
 
                     if (bm != null) {
@@ -1569,7 +1637,7 @@
                         Styled.measureText(paint, workPaint, text,
                                            j, j + 2, null);
 
-                        float wid = (float) bm.getWidth() *
+                        float wid = bm.getWidth() *
                                     -workPaint.ascent() / bm.getHeight();
 
                         if (dir == DIR_RIGHT_TO_LEFT) {
@@ -1584,8 +1652,6 @@
                     segstart = j + 1;
                 }
             }
-
-            here = there;
         }
 
         if (hasTabs)
@@ -1616,7 +1682,7 @@
                                            Paint.FontMetricsInt fm,
                                            boolean hasTabs, Object[] tabs) {
         char[] buf = null;
-  
+
         if (hasTabs) {
             buf = TextUtils.obtain(end - start);
             TextUtils.getChars(text, start, end, buf, 0);
@@ -1652,6 +1718,8 @@
             if (pos == len || codept == '\t' || bm != null) {
                 workPaint.baselineShift = 0;
 
+                // XXX Styled.measureText assumes the run direction is LTR,
+                // but it might not be.  Check this.
                 width += Styled.measureText(paint, workPaint, text,
                                         start + lastPos, start + pos,
                                         fm);
@@ -1683,7 +1751,7 @@
                         Styled.measureText(paint, workPaint, text,
                                            start + pos, start + pos + 1, null);
 
-                        width += (float) bm.getWidth() *
+                        width += bm.getWidth() *
                                     -workPaint.ascent() / bm.getHeight();
 
                         // Since we had an emoji, we bump past the second half
@@ -1804,23 +1872,22 @@
 
     /**
      * Stores information about bidirectional (left-to-right or right-to-left)
-     * text within the layout of a line.  TODO: This work is not complete
-     * or correct and will be fleshed out in a later revision.
+     * text within the layout of a line.
      */
     public static class Directions {
-        private short[] mDirections;
+        // Directions represents directional runs within a line of text.
+        // Runs are pairs of ints listed in visual order, starting from the
+        // leading margin.  The first int of each pair is the offset from
+        // the first character of the line to the start of the run.  The
+        // second int represents both the length and level of the run.
+        // The length is in the lower bits, accessed by masking with
+        // DIR_LENGTH_MASK.  The level is in the higher bits, accessed
+        // by shifting by DIR_LEVEL_SHIFT and masking by DIR_LEVEL_MASK.
+        // To simply test for an RTL direction, test the bit using
+        // DIR_RTL_FLAG, if set then the direction is rtl.
 
-        // 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) {
+        /* package */ int[] mDirections;
+        /* package */ Directions(int[] dirs) {
             mDirections = dirs;
         }
     }
@@ -1870,7 +1937,7 @@
         public int length() {
             return mText.length();
         }
-    
+
         public CharSequence subSequence(int start, int end) {
             char[] s = new char[end - start];
             getChars(start, end, s, 0);
@@ -1936,12 +2003,17 @@
 
     public static final int DIR_LEFT_TO_RIGHT = 1;
     public static final int DIR_RIGHT_TO_LEFT = -1;
-    
+
     /* package */ static final int DIR_REQUEST_LTR = 1;
     /* package */ static final int DIR_REQUEST_RTL = -1;
     /* package */ static final int DIR_REQUEST_DEFAULT_LTR = 2;
     /* package */ static final int DIR_REQUEST_DEFAULT_RTL = -2;
 
+    /* package */ static final int RUN_LENGTH_MASK = 0x03ffffff;
+    /* package */ static final int RUN_LEVEL_SHIFT = 26;
+    /* package */ static final int RUN_LEVEL_MASK = 0x3f;
+    /* package */ static final int RUN_RTL_FLAG = 1 << RUN_LEVEL_SHIFT;
+
     public enum Alignment {
         ALIGN_NORMAL,
         ALIGN_OPPOSITE,
@@ -1953,9 +2025,8 @@
     private static final int TAB_INCREMENT = 20;
 
     /* package */ static final Directions DIRS_ALL_LEFT_TO_RIGHT =
-                                       new Directions(new short[] { 32767 });
+        new Directions(new int[] { 0, RUN_LENGTH_MASK });
     /* package */ static final Directions DIRS_ALL_RIGHT_TO_LEFT =
-                                       new Directions(new short[] { 0, 32767 });
-
+        new Directions(new int[] { 0, RUN_LENGTH_MASK | RUN_RTL_FLAG });
 }
 
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index f02ad2a..bfa0ab6 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -16,14 +16,15 @@
 
 package android.text;
 
+import com.android.internal.util.ArrayUtils;
+
 import android.graphics.Bitmap;
 import android.graphics.Paint;
-import com.android.internal.util.ArrayUtils;
-import android.util.Log;
 import android.text.style.LeadingMarginSpan;
 import android.text.style.LineHeightSpan;
 import android.text.style.MetricAffectingSpan;
 import android.text.style.ReplacementSpan;
+import android.util.Log;
 
 /**
  * StaticLayout is a Layout for text that will not be edited after it
@@ -31,8 +32,9 @@
  * <p>This is used by widgets to control text layout. You should not need
  * to use this class directly unless you are implementing your own widget
  * or custom display object, or would be tempted to call
- * {@link android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint)
- *  Canvas.drawText()} directly.</p>
+ * {@link android.graphics.Canvas#drawText(java.lang.CharSequence, int, int,
+ * float, float, android.graphics.Paint)
+ * Canvas.drawText()} directly.</p>
  */
 public class
 StaticLayout
@@ -62,7 +64,7 @@
                         boolean includepad,
                         TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
         super((ellipsize == null)
-                ? source 
+                ? source
                 : (source instanceof Spanned)
                     ? new SpannedEllipsizer(source)
                     : new Ellipsizer(source),
@@ -72,7 +74,7 @@
          * This is annoying, but we can't refer to the layout until
          * superclass construction is finished, and the superclass
          * constructor wants the reference to the display text.
-         * 
+         *
          * This will break if the superclass constructor ever actually
          * cares about the content instead of just holding the reference.
          */
@@ -196,7 +198,7 @@
                             // starts in this layout, before the
                             // current paragraph
 
-                            choosehtv[i] = getLineTop(getLineForOffset(o)); 
+                            choosehtv[i] = getLineTop(getLineForOffset(o));
                         } else {
                             // starts in this paragraph
 
@@ -224,7 +226,7 @@
 
             boolean easy = true;
             boolean altered = false;
-            int dir = DEFAULT_DIR; // XXX
+            int dir = DEFAULT_DIR; // XXX pass value in
 
             for (int i = 0; i < n; i++) {
                 if (chs[i] >= FIRST_RIGHT_TO_LEFT) {
@@ -253,7 +255,8 @@
 
             if (!easy) {
                 // XXX put override flags, etc. into chdirs
-                dir = bidi(dir, chs, chdirs, n, false);
+                // XXX supply dir rather than force
+                dir = AndroidBidi.bidi(DIR_REQUEST_DEFAULT_LTR, chs, chdirs, n, false);
 
                 // Do mirroring for right-to-left segments
 
@@ -316,7 +319,7 @@
                     paint.getTextWidths(sub, i, next, widths);
                     System.arraycopy(widths, 0, widths,
                                      end - start + (i - start), next - i);
-                                     
+
                     paint.getFontMetricsInt(fm);
                 } else {
                     mWorkPaint.baselineShift = 0;
@@ -376,7 +379,7 @@
                                     whichPaint = mWorkPaint;
                                 }
 
-                                float wid = (float) bm.getWidth() *
+                                float wid = bm.getWidth() *
                                             -whichPaint.ascent() /
                                             bm.getHeight();
 
@@ -411,7 +414,7 @@
                         /*
                          * From the Unicode Line Breaking Algorithm:
                          * (at least approximately)
-                         *  
+                         *
                          * .,:; are class IS: breakpoints
                          *      except when adjacent to digits
                          * /    is class SY: a breakpoint
@@ -606,239 +609,6 @@
         }
     }
 
-    /**
-     * Runs the unicode bidi algorithm on the first n chars in chs, returning
-     * the char dirs in chInfo and the base line direction of the first
-     * paragraph.
-     * 
-     * XXX change result from dirs to levels
-     *  
-     * @param dir the direction flag, either DIR_REQUEST_LTR,
-     * DIR_REQUEST_RTL, DIR_REQUEST_DEFAULT_LTR, or DIR_REQUEST_DEFAULT_RTL.
-     * @param chs the text to examine
-     * @param chInfo on input, if hasInfo is true, override and other flags 
-     * representing out-of-band embedding information. On output, the generated 
-     * dirs of the text.
-     * @param n the length of the text/information in chs and chInfo
-     * @param hasInfo true if chInfo has input information, otherwise the
-     * input data in chInfo is ignored.
-     * @return the resolved direction level of the first paragraph, either
-     * DIR_LEFT_TO_RIGHT or DIR_RIGHT_TO_LEFT.
-     */
-    /* package */ static int bidi(int dir, char[] chs, byte[] chInfo, int n, 
-            boolean hasInfo) {
-        
-        AndroidCharacter.getDirectionalities(chs, chInfo, n);
-
-        /*
-         * Determine primary paragraph direction if not specified
-         */
-        if (dir != DIR_REQUEST_LTR && dir != DIR_REQUEST_RTL) {
-            // set up default
-            dir = dir >= 0 ? DIR_LEFT_TO_RIGHT : DIR_RIGHT_TO_LEFT;
-            for (int j = 0; j < n; j++) {
-                int d = chInfo[j];
-
-                if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT) {
-                    dir = DIR_LEFT_TO_RIGHT;
-                    break;
-                }
-                if (d == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
-                    dir = DIR_RIGHT_TO_LEFT;
-                    break;
-                }
-            }
-        }
-
-        final byte SOR = dir == DIR_LEFT_TO_RIGHT ?
-                Character.DIRECTIONALITY_LEFT_TO_RIGHT :
-                Character.DIRECTIONALITY_RIGHT_TO_LEFT;
-
-        /*
-         * XXX Explicit overrides should go here
-         */
-
-        /*
-         * Weak type resolution
-         */
-
-        // dump(chdirs, n, "initial");
-
-        // W1 non spacing marks
-        for (int j = 0; j < n; j++) {
-            if (chInfo[j] == Character.NON_SPACING_MARK) {
-                if (j == 0)
-                    chInfo[j] = SOR;
-                else
-                    chInfo[j] = chInfo[j - 1];
-            }
-        }
-
-        // dump(chdirs, n, "W1");
-
-        // W2 european numbers
-        byte cur = SOR;
-        for (int j = 0; j < n; j++) {
-            byte d = chInfo[j];
-
-            if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT ||
-                d == Character.DIRECTIONALITY_RIGHT_TO_LEFT ||
-                d == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC)
-                cur = d;
-            else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER) {
-                 if (cur ==
-                    Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC)
-                    chInfo[j] = Character.DIRECTIONALITY_ARABIC_NUMBER;
-            }
-        }
-
-        // dump(chdirs, n, "W2");
-
-        // W3 arabic letters
-        for (int j = 0; j < n; j++) {
-            if (chInfo[j] == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC)
-                chInfo[j] = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
-        }
-
-        // dump(chdirs, n, "W3");
-
-        // W4 single separator between numbers
-        for (int j = 1; j < n - 1; j++) {
-            byte d = chInfo[j];
-            byte prev = chInfo[j - 1];
-            byte next = chInfo[j + 1];
-
-            if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR) {
-                if (prev == Character.DIRECTIONALITY_EUROPEAN_NUMBER &&
-                    next == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
-                    chInfo[j] = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
-            } else if (d == Character.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR) {
-                if (prev == Character.DIRECTIONALITY_EUROPEAN_NUMBER &&
-                    next == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
-                    chInfo[j] = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
-                if (prev == Character.DIRECTIONALITY_ARABIC_NUMBER &&
-                    next == Character.DIRECTIONALITY_ARABIC_NUMBER)
-                    chInfo[j] = Character.DIRECTIONALITY_ARABIC_NUMBER;
-            }
-        }
-
-        // dump(chdirs, n, "W4");
-
-        // W5 european number terminators
-        boolean adjacent = false;
-        for (int j = 0; j < n; j++) {
-            byte d = chInfo[j];
-
-            if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
-                adjacent = true;
-            else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR && adjacent)
-                chInfo[j] = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
-            else
-                adjacent = false;
-        }
-
-        //dump(chdirs, n, "W5");
-
-        // W5 european number terminators part 2,
-        // W6 separators and terminators
-        adjacent = false;
-        for (int j = n - 1; j >= 0; j--) {
-            byte d = chInfo[j];
-
-            if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
-                adjacent = true;
-            else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR) {
-                if (adjacent)
-                    chInfo[j] = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
-                else
-                    chInfo[j] = Character.DIRECTIONALITY_OTHER_NEUTRALS;
-            }
-            else {
-                adjacent = false;
-
-                if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR ||
-                    d == Character.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR ||
-                    d == Character.DIRECTIONALITY_PARAGRAPH_SEPARATOR ||
-                    d == Character.DIRECTIONALITY_SEGMENT_SEPARATOR)
-                    chInfo[j] = Character.DIRECTIONALITY_OTHER_NEUTRALS;
-            }
-        }
-
-        // dump(chdirs, n, "W6");
-
-        // W7 strong direction of european numbers
-        cur = SOR;
-        for (int j = 0; j < n; j++) {
-            byte d = chInfo[j];
-
-            if (d == SOR ||
-                d == Character.DIRECTIONALITY_LEFT_TO_RIGHT ||
-                d == Character.DIRECTIONALITY_RIGHT_TO_LEFT)
-                cur = d;
-
-            if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
-                chInfo[j] = cur;
-        }
-
-        // dump(chdirs, n, "W7");
-
-        // N1, N2 neutrals
-        cur = SOR;
-        for (int j = 0; j < n; j++) {
-            byte d = chInfo[j];
-
-            if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT ||
-                d == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
-                cur = d;
-            } else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER ||
-                       d == Character.DIRECTIONALITY_ARABIC_NUMBER) {
-                cur = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
-            } else {
-                byte dd = SOR;
-                int k;
-
-                for (k = j + 1; k < n; k++) {
-                    dd = chInfo[k];
-
-                    if (dd == Character.DIRECTIONALITY_LEFT_TO_RIGHT ||
-                        dd == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
-                        break;
-                    }
-                    if (dd == Character.DIRECTIONALITY_EUROPEAN_NUMBER ||
-                        dd == Character.DIRECTIONALITY_ARABIC_NUMBER) {
-                        dd = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
-                        break;
-                    }
-                }
-
-                for (int y = j; y < k; y++) {
-                    if (dd == cur)
-                        chInfo[y] = cur;
-                    else
-                        chInfo[y] = SOR;
-                }
-
-                j = k - 1;
-            }
-        }
-
-        // dump(chdirs, n, "final");
-
-        // extra: enforce that all tabs and surrogate characters go the
-        // primary direction
-        // TODO: actually do directions right for surrogates
-
-        for (int j = 0; j < n; j++) {
-            char c = chs[j];
-
-            if (c == '\t' || (c >= 0xD800 && c <= 0xDFFF)) {
-                chInfo[j] = SOR;
-            }
-        }
-        
-        return dir;
-    }
-
     private static final char FIRST_CJK = '\u2E80';
     /**
      * Returns true if the specified character is one of those specified
@@ -1062,49 +832,123 @@
         if (tab)
             lines[off + TAB] |= TAB_MASK;
 
-        {
-            lines[off + DIR] |= dir << DIR_SHIFT;
-
-            int cur = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
-            int count = 0;
-
-            if (!easy) {
-                for (int k = start; k < end; k++) {
-                    if (chdirs[k - pstart] != cur) {
-                        count++;
-                        cur = chdirs[k - pstart];
-                    }
+        lines[off + DIR] |= dir << DIR_SHIFT;
+        Directions linedirs = DIRS_ALL_LEFT_TO_RIGHT;
+        // easy means all chars < the first RTL, so no emoji, no nothing
+        // XXX a run with no text or all spaces is easy but might be an empty
+        // RTL paragraph.  Make sure easy is false if this is the case.
+        if (easy) {
+            mLineDirections[j] = linedirs;
+        } else {
+            int startOff = start - pstart;
+            int baseLevel = dir == DIR_LEFT_TO_RIGHT ? 0 : 1;
+            int curLevel = chdirs[startOff];
+            int minLevel = curLevel;
+            int runCount = 1;
+            for (int i = start + 1; i < end; ++i) {
+                int level = chdirs[i - pstart];
+                if (level != curLevel) {
+                    curLevel = level;
+                    ++runCount;
                 }
             }
 
-            Directions linedirs;
+            // add final run for trailing counter-directional whitespace
+            int visEnd = end;
+            if ((curLevel & 1) != (baseLevel & 1)) {
+                // look for visible end
+                while (--visEnd >= start) {
+                    char ch = text.charAt(visEnd);
 
-            if (count == 0) {
-                linedirs = DIRS_ALL_LEFT_TO_RIGHT;
+                    if (ch == '\n') {
+                        --visEnd;
+                        break;
+                    }
+
+                    if (ch != ' ' && ch != '\t') {
+                        break;
+                    }
+                }
+                ++visEnd;
+                if (visEnd != end) {
+                    ++runCount;
+                }
+            }
+
+            if (runCount == 1 && minLevel == baseLevel) {
+                if ((minLevel & 1) != 0) {
+                    linedirs = DIRS_ALL_RIGHT_TO_LEFT;
+                }
+                // we're done, only one run on this line
             } else {
-                short[] ld = new short[count + 1];
-
-                cur = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
-                count = 0;
-                int here = start;
-
-                for (int k = start; k < end; k++) {
-                    if (chdirs[k - pstart] != cur) {
-                        // XXX check to make sure we don't
-                        //     overflow short
-                        ld[count++] = (short) (k - here);
-                        cur = chdirs[k - pstart];
-                        here = k;
+                int[] ld = new int[runCount * 2];
+                int maxLevel = minLevel;
+                int levelBits = minLevel << RUN_LEVEL_SHIFT;
+                {
+                    // Start of first pair is always 0, we write
+                    // length then start at each new run, and the
+                    // last run length after we're done.
+                    int n = 1;
+                    int prev = start;
+                    curLevel = minLevel;
+                    for (int i = start; i < visEnd; ++i) {
+                        int level = chdirs[i - pstart];
+                        if (level != curLevel) {
+                            curLevel = level;
+                            if (level > maxLevel) {
+                                maxLevel = level;
+                            } else if (level < minLevel) {
+                                minLevel = level;
+                            }
+                            // XXX ignore run length limit of 2^RUN_LEVEL_SHIFT
+                            ld[n++] = (i - prev) | levelBits;
+                            ld[n++] = i - start;
+                            levelBits = curLevel << RUN_LEVEL_SHIFT;
+                            prev = i;
+                        }
+                    }
+                    ld[n] = (visEnd - prev) | levelBits;
+                    if (visEnd < end) {
+                        ld[++n] = visEnd - start;
+                        ld[++n] = (end - visEnd) | (baseLevel << RUN_LEVEL_SHIFT);
                     }
                 }
 
-                ld[count] = (short) (end - here);
-
-                if (count == 1 && ld[0] == 0) {
-                    linedirs = DIRS_ALL_RIGHT_TO_LEFT;
+                // See if we need to swap any runs.
+                // If the min level run direction doesn't match the base
+                // direction, we always need to swap (at this point
+                // we have more than one run).
+                // Otherwise, we don't need to swap the lowest level.
+                // Since there are no logically adjacent runs at the same
+                // level, if the max level is the same as the (new) min
+                // level, we have a series of alternating levels that
+                // is already in order, so there's no more to do.
+                //
+                boolean swap;
+                if ((minLevel & 1) == baseLevel) {
+                    minLevel += 1;
+                    swap = maxLevel > minLevel;
                 } else {
-                    linedirs = new Directions(ld);
+                    swap = runCount > 1;
                 }
+                if (swap) {
+                    for (int level = maxLevel - 1; level >= minLevel; --level) {
+                        for (int i = 0; i < ld.length; i += 2) {
+                            if (chdirs[startOff + ld[i]] >= level) {
+                                int e = i + 2;
+                                while (e < ld.length && chdirs[startOff + ld[e]] >= level) {
+                                    e += 2;
+                                }
+                                for (int low = i, hi = e - 2; low < hi; low += 2, hi -= 2) {
+                                    int x = ld[low]; ld[low] = ld[hi]; ld[hi] = x;
+                                    x = ld[low+1]; ld[low+1] = ld[hi+1]; ld[hi+1] = x;
+                                }
+                                i = e + 2;
+                            }
+                        }
+                    }
+                }
+                linedirs = new Directions(ld);
             }
 
             mLineDirections[j] = linedirs;
@@ -1232,11 +1076,11 @@
     }
 
     public int getLineTop(int line) {
-        return mLines[mColumns * line + TOP];    
+        return mLines[mColumns * line + TOP];
     }
 
     public int getLineDescent(int line) {
-        return mLines[mColumns * line + DESCENT];   
+        return mLines[mColumns * line + DESCENT];
     }
 
     public int getLineStart(int line) {
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 66461a7..dafceb6 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -559,6 +559,16 @@
 
         boolean smoothScrollbar = a.getBoolean(R.styleable.AbsListView_smoothScrollbar, true);
         setSmoothScrollbarEnabled(smoothScrollbar);
+        
+        final int adapterId = a.getResourceId(R.styleable.AbsListView_adapter, 0);
+        if (adapterId != 0) {
+            final Context c = context;
+            post(new Runnable() {
+                public void run() {
+                    setAdapter(Adapters.loadAdapter(c, adapterId));
+                }
+            });
+        }
 
         a.recycle();
     }
diff --git a/core/java/android/widget/Adapters.java b/core/java/android/widget/Adapters.java
new file mode 100644
index 0000000..05e501a
--- /dev/null
+++ b/core/java/android/widget/Adapters.java
@@ -0,0 +1,1191 @@
+/*
+ * 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 android.widget;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.database.Cursor;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.util.AttributeSet;
+import android.util.Xml;
+import android.view.View;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import static com.android.internal.R.*;
+
+/**
+ * <p>This class can be used to load {@link android.widget.Adapter adapters} defined in
+ * XML resources. XML-defined adapters can be used to easily create adapters in your
+ * own application or to pass adapters to other processes.</p>
+ * 
+ * <h2>Types of adapters</h2>
+ * <p>Adapters defined using XML resources can only be one of the following supported
+ * types. Arbitrary adapters are not supported to guarantee the safety of the loaded
+ * code when adapters are loaded across packages.</p>
+ * <ul>
+ *  <li><a href="#xml-cursor-adapter">Cursor adapter</a>: a cursor adapter can be used
+ *  to display the content of a cursor, most often coming from a content provider</li>
+ * </ul>
+ * <p>The complete XML format definition of each adapter type is available below.</p>
+ * 
+ * <a name="xml-cursor-adapter" />
+ * <h2>Cursor adapter</h2>
+ * <p>A cursor adapter XML definition starts with the
+ * <a href="#xml-cursor-adapter-tag"><code>&lt;cursor-adapter /&gt;</code></a>
+ * tag and may contain one or more instances of the following tags:</p>
+ * <ul>
+ *  <li><a href="#xml-cursor-adapter-select-tag"><code>&lt;select /&gt;</code></a></li>
+ *  <li><a href="#xml-cursor-adapter-bind-tag"><code>&lt;bind /&gt;</code></a></li>
+ * </ul>
+ * 
+ * <a name="xml-cursor-adapter-tag" />
+ * <h3>&lt;cursor-adapter /&gt;</h3>
+ * <p>The <code>&lt;cursor-adapter /&gt;</code> element defines the beginning of the
+ * document and supports the following attributes:</p>
+ * <ul>
+ *  <li><code>android:layout</code>: Reference to the XML layout to be inflated for
+ *  each item of the adapter. This attribute is mandatory.</li>
+ *  <li><code>android:selection</code>: Selection expression, used when the
+ *  <code>android:uri</code> attribute is defined or when the adapter is loaded with
+ *  {@link android.widget.Adapters#loadCursorAdapter(android.content.Context, int, String, Object[])}.
+ *  This attribute is optional.</li>
+ *  <li><code>android:sortOrder</code>: Sort expression, used when the
+ *  <code>android:uri</code> attribute is defined or when the adapter is loaded with
+ *  {@link android.widget.Adapters#loadCursorAdapter(android.content.Context, int, String, Object[])}.
+ *  This attribute is optional.</li>
+ *  <li><code>android:uri</code>: URI of the content provider to query to retrieve a cursor.
+ *  Specifying this attribute is equivalent to calling {@link android.widget.Adapters#loadCursorAdapter(android.content.Context, int, String, Object[])}.
+ *  If you call this method, the value of the XML attribute is ignored. This attribute is
+ *  optional.</li>
+ * </ul>
+ * <p>In addition, you can specify one or more instances of
+ * <a href="#xml-cursor-adapter-select-tag"><code>&lt;select /&gt;</code></a> and
+ * <a href="#xml-cursor-adapter-bind-tag"><code>&lt;bind /&gt;</code></a> tags as children
+ * of <code>&lt;cursor-adapter /&gt;</code>.</p>
+ * 
+ * <a name="xml-cursor-adapter-select-tag" />
+ * <h3>&lt;select /&gt;</h3>
+ * <p>The <code>&lt;select /&gt;</code> tag is used to select columns from the cursor
+ * when doing the query. This can be very useful when using transformations in the
+ * <code>&lt;bind /&gt;</code> elements. It can also be very useful if you are providing
+ * your own <a href="#xml-cursor-adapter-bind-data-types">binder</a> or
+ * <a href="#xml-cursor-adapter-bind-data-types">transformation</a> classes.
+ * <code>&lt;select /&gt;</code> elements are ignored if you supply the cursor yourself.</p>
+ * <p>The <code>&lt;select /&gt;</code> supports the following attributes:</p>
+ * <ul>
+ *  <li><code>android:column</code>: Name of the column to select in the cursor during the
+ *  query operation</li>
+ * </ul>
+ * <p><strong>Note:</strong> The column named <code>_id</code> is always implicitely
+ * selected.</p>
+ * 
+ * <a name="xml-cursor-adapter-bind-tag" />
+ * <h3>&lt;bind /&gt;</h3>
+ * <p>The <code>&lt;bind /&gt;</code> tag is used to bind a column from the cursor to
+ * a {@link android.view.View}. A column bound using this tag is automatically selected
+ * during the query and a matching
+ * <a href="#xml-cursor-adapter-select-tag"><code>&lt;select /&gt;</code> tag is therefore
+ * not required.</p>
+ * 
+ * <p>Each binding is declared as a one to one matching but
+ * custom binder classes or special
+ * <a href="#xml-cursor-adapter-bind-data-transformation">data transformations</a> can
+ * allow you to bind several columns to a single view. In this case you must use the
+ * <a href="#xml-cursor-adapter-select-tag"><code>&lt;select /&gt;</code> tag to make
+ * sure any required column is part of the query.</p>
+ * 
+ * <p>The <code>&lt;bind /&gt;</code> tag supports the following attributes:</p>
+ * <ul>
+ *  <li><code>android:from</code>: The name of the column to bind from.
+ *  This attribute is mandatory.</li>
+ *  <li><code>android:to</code>: The id of the view to bind to. This attribute is mandatory.</li>
+ *  <li><code>android:as</code>: The <a href="#xml-cursor-adapter-bind-data-types">data type</a>
+ *  of the binding. This attribute is mandatory.</li>
+ * </ul>
+ * 
+ * <p>In addition, a <code>&lt;bind /&gt;</code> can contain zero or more instances of
+ * <a href="#xml-cursor-adapter-bind-data-transformation">data transformations</a> chilren
+ * tags.</p>
+ *
+ * <a name="xml-cursor-adapter-bind-data-types" />
+ * <h4>Binding data types</h4>
+ * <p>For a binding to occur the data type of the bound column/view pair must be specified.
+ * The following data types are currently supported:</p>
+ * <ul>
+ *  <li><code>string</code>: The content of the column is interpreted as a string and must be
+ *  bound to a {@link android.widget.TextView}</li>
+ *  <li><code>image</code>: The content of the column is interpreted as a blob describing an
+ *  image and must be bound to an {@link android.widget.ImageView}</li>
+ *  <li><code>image-uri</code>: The content of the column is interpreted as a URI to an image
+ *  and must be bound to an {@link android.widget.ImageView}</li>
+ *  <li><code>drawable</code>: The content of the column is interpreted as a resource id to a
+ *  drawable and must be bound to an {@link android.widget.ImageView}</li>
+ *  <li>A fully qualified class name: The name of a class corresponding to an implementation of
+ *  {@link android.widget.Adapters.CursorBinder}. Cursor binders can be used to provide
+ *  bindings not supported by default. Custom binders cannot be used with
+ *  {@link android.content.Context#isRestricted() restricted contexts}, for instance in an
+ *  app widget</li>
+ * </ul>
+ * 
+ * <a name="xml-cursor-adapter-bind-transformation" />
+ * <h4>Binding transformations</h4>
+ * <p>When defining a data binding you can specify an optional transformation by using one
+ * of the following tags as a child of a <code>&lt;bind /&gt;</code> elements:</p>
+ * <ul>
+ *  <li><code>&lt;map /&gt;</code>: Maps a constant string to a string or a resource. Use
+ *  one instance of this tag per value you want to map</li>
+ *  <li><code>&lt;transform /&gt;</code>: Transforms a column's value using an expression
+ *  or an instance of {@link android.widget.Adapters.CursorTransformation}</li>
+ * </ul>
+ * <p>While several <code>&lt;map /&gt;</code> tags can be used at the same time, you cannot
+ * mix <code>&lt;map /&gt;</code> and <code>&lt;transform /&gt;</code> tags. If several
+ * <code>&lt;transform /&gt;</code> tags are specified, only the last one is retained.</p>
+ * 
+ * <a name="xml-cursor-adapter-bind-transformation-map" />
+ * <p><strong>&lt;map /&gt;</strong></p>
+ * <p>A map element simply specifies a value to match from and a value to match to. When
+ * a column's value equals the value to match from, it is replaced with the value to match
+ * to. The following attributes are supported:</p>
+ * <ul>
+ *  <li><code>android:fromValue</code>: The value to match from. This attribute is mandatory</li>
+ *  <li><code>android:toValue</code>: The value to match to. This value can be either a string
+ *  or a resource identifier. This value is interpreted as a resource identifier when the
+ *  data binding is of type <code>drawable</code>. This attribute is mandatory</li>
+ * </ul>
+ * 
+ * <a name="xml-cursor-adapter-bind-transformation-transform" />
+ * <p><strong>&lt;transform /&gt;</strong></p>
+ * <p>A simple transform that occurs either by calling a specified class or by performing
+ * simple text substitution. The following attributes are supported:</p>
+ * <ul>
+ *  <li><code>android:withExpression</code>: The transformation expression. The expression is
+ *  a string containing column names surrounded with curly braces { and }. During the
+ *  transformation each column name is replaced by its value. All columns must have been
+ *  selected in the query. An example of expression is <code>"First name: {first_name},
+ *  last name: {last_name}"</code>. This attribute is mandatory
+ *  if <code>android:withClass</code> is not specified and ignored if <code>android:withClass</code>
+ *  is specified</li>
+ *  <li><code>android:withClass</code>: A fully qualified class name corresponding to an
+ *  implementation of {@link android.widget.Adapters.CursorTransformation}. Custom
+ *  transformationscannot be used with
+ *  {@link android.content.Context#isRestricted() restricted contexts}, for instance in
+ *  an app widget This attribute is mandatory if <code>android:withExpression</code> is
+ *  not specified</li>
+ * </ul>
+ * 
+ * <h3>Example</h3>
+ * <p>The following example defines a cursor adapter that queries all the contacts with
+ * a phone number using the contacts content provider. Each contact is displayed with
+ * its display name, its favorite status and its photo. To display photos, a custom data
+ * binder is declared:</p>
+ * 
+ * <pre class="prettyprint">
+ * &lt;cursor-adapter xmlns:android="http://schemas.android.com/apk/res/android"
+ *     android:uri="content://com.android.contacts/contacts"
+ *     android:selection="has_phone_number=1"
+ *     android:layout="@layout/contact_item"&gt;
+ *
+ *     &lt;bind android:from="display_name" android:to="@id/name" android:as="string" /&gt;
+ *     &lt;bind android:from="starred" android:to="@id/star" android:as="drawable"&gt;
+ *         &lt;map android:fromValue="0" android:toValue="@android:drawable/star_big_off" /&gt;
+ *         &lt;map android:fromValue="1" android:toValue="@android:drawable/star_big_on" /&gt;
+ *     &lt;/bind&gt;
+ *     &lt;bind android:from="_id" android:to="@id/name"
+ *              android:as="com.google.android.test.adapters.ContactPhotoBinder" /&gt;
+ *
+ * &lt;/cursor-adapter&gt;
+ * </pre>
+ * 
+ * <h3>Related APIs</h3>
+ * <ul>
+ *  <li>{@link android.widget.Adapters#loadAdapter(android.content.Context, int, Object[])}</li>
+ *  <li>{@link android.widget.Adapters#loadCursorAdapter(android.content.Context, int, android.database.Cursor, Object[])}</li>
+ *  <li>{@link android.widget.Adapters#loadCursorAdapter(android.content.Context, int, String, Object[])}</li>
+ *  <li>{@link android.widget.Adapters.CursorBinder}</li>
+ *  <li>{@link android.widget.Adapters.CursorTransformation}</li>
+ *  <li>{@link android.widget.CursorAdapter}</li>
+ * </ul>
+ * 
+ * @see android.widget.Adapter
+ * @see android.content.ContentProvider
+ * 
+ * @attr ref android.R.styleable#CursorAdapter_layout 
+ * @attr ref android.R.styleable#CursorAdapter_selection 
+ * @attr ref android.R.styleable#CursorAdapter_sortOrder 
+ * @attr ref android.R.styleable#CursorAdapter_uri 
+ * @attr ref android.R.styleable#CursorAdapter_BindItem_as 
+ * @attr ref android.R.styleable#CursorAdapter_BindItem_from 
+ * @attr ref android.R.styleable#CursorAdapter_BindItem_to
+ * @attr ref android.R.styleable#CursorAdapter_MapItem_fromValue 
+ * @attr ref android.R.styleable#CursorAdapter_MapItem_toValue 
+ * @attr ref android.R.styleable#CursorAdapter_SelectItem_column 
+ * @attr ref android.R.styleable#CursorAdapter_TransformItem_withClass 
+ * @attr ref android.R.styleable#CursorAdapter_TransformItem_withExpression 
+ */
+@SuppressWarnings({"JavadocReference"})
+public class Adapters {
+    private static final String ADAPTER_CURSOR = "cursor-adapter";
+
+    /**
+     * <p>Interface used to bind a {@link android.database.Cursor} column to a View. This
+     * interface can be used to provide bindings for data types not supported by the
+     * standard implementation of {@link android.widget.Adapters}.</p>
+     * 
+     * <p>A binder is provided with a cursor transformation which may or may not be used
+     * to transform the value retrieved from the cursor. The transformation is guaranteed
+     * to never be null so it's always safe to apply the transformation.</p>
+     * 
+     * <p>The binder is associated with a Context but can be re-used with multiple cursors.
+     * As such, the implementation should make no assumption about the Cursor in use.</p>
+     *
+     * @see android.view.View 
+     * @see android.database.Cursor
+     * @see android.widget.Adapters.CursorTransformation
+     */
+    public static abstract class CursorBinder {
+        /**
+         * <p>The context associated with this binder.</p>
+         */
+        protected final Context mContext;
+
+        /**
+         * <p>The transformation associated with this binder. This transformation is never
+         * null and may or may not be applied to the Cursor data during the
+         * {@link #bind(android.view.View, android.database.Cursor, int)} operation.</p>
+         * 
+         * @see #bind(android.view.View, android.database.Cursor, int) 
+         */
+        protected final CursorTransformation mTransformation;
+
+        /**
+         * <p>Creates a new Cursor binder.</p> 
+         * 
+         * @param context The context associated with this binder.
+         * @param transformation The transformation associated with this binder. This
+         *        transformation may or may not be applied by the binder and is guaranteed
+         *        to not be null.
+         */
+        public CursorBinder(Context context, CursorTransformation transformation) {
+            mContext = context;
+            mTransformation = transformation;
+        }
+
+        /**
+         * <p>Binds the specified Cursor column to the supplied View. The binding operation
+         * can query other Cursor columns as needed. During the binding operation, values
+         * retrieved from the Cursor may or may not be transformed using this binder's
+         * cursor transformation.</p>
+         * 
+         * @param view The view to bind data to.
+         * @param cursor The cursor to bind data from.
+         * @param columnIndex The column index in the cursor where the data to bind resides.
+         * 
+         * @see #mTransformation
+         * 
+         * @return True if the column was successfully bound to the View, false otherwise.
+         */
+        public abstract boolean bind(View view, Cursor cursor, int columnIndex);
+    }
+
+    /**
+     * <p>Interface used to transform data coming out of a {@link android.database.Cursor}
+     * before it is bound to a {@link android.view.View}.</p>
+     * 
+     * <p>Transformations are used to transform text-based data (in the form of a String),
+     * or to transform data into a resource identifier. A default implementation is provided
+     * to generate resource identifiers.</p>
+     * 
+     * @see android.database.Cursor
+     * @see android.widget.Adapters.CursorBinder
+     */
+    public static abstract class CursorTransformation {
+        /**
+         * <p>The context associated with this transformation.</p>
+         */
+        protected final Context mContext;
+
+        /**
+         * <p>Creates a new Cursor transformation.</p>
+         * 
+         * @param context The context associated with this transformation.
+         */
+        public CursorTransformation(Context context) {
+            mContext = context;
+        }
+
+        /**
+         * <p>Transforms the specified Cursor column into a String. The transformation
+         * can simply return the content of the column as a String (this is known
+         * as the identity transformation) or manipulate the content. For instance,
+         * a transformation can perform text substitutions or concatenate other
+         * columns with the specified column.</p>
+         * 
+         * @param cursor The cursor that contains the data to transform. 
+         * @param columnIndex The index of the column to transform.
+         * 
+         * @return A String containing the transformed value of the column.
+         */
+        public abstract String transform(Cursor cursor, int columnIndex);
+
+        /**
+         * <p>Transforms the specified Cursor column into a resource identifier.
+         * The default implementation simply interprets the content of the column
+         * as an integer.</p>
+         * 
+         * @param cursor The cursor that contains the data to transform. 
+         * @param columnIndex The index of the column to transform.
+         * 
+         * @return A resource identifier.
+         */
+        public int transformToResource(Cursor cursor, int columnIndex) {
+            return cursor.getInt(columnIndex);
+        }        
+    }
+
+    /**
+     * <p>Loads the {@link android.widget.CursorAdapter} defined in the specified
+     * XML resource. The content of the adapter is loaded from the content provider
+     * identified by the supplied URI.</p>
+     * 
+     * <p><strong>Note:</strong> If the supplied {@link android.content.Context} is
+     * an {@link android.app.Activity}, the cursor returned by the content provider
+     * will be automatically managed. Otherwise, you are responsible for managing the
+     * cursor yourself.</p>
+     * 
+     * <p>The format of the XML definition of the cursor adapter is documented at
+     * the top of this page.</p>
+     * 
+     * @param context The context to load the XML resource from.
+     * @param id The identifier of the XML resource declaring the adapter.
+     * @param uri The URI of the content provider.
+     * @param parameters Optional parameters to pass to the CursorAdapter, used
+     *        to substitute values in the selection expression.
+     * 
+     * @return A {@link android.widget.CursorAdapter}
+     * 
+     * @throws IllegalArgumentException If the XML resource does not contain
+     *         a valid &lt;cursor-adapter /&gt; definition.
+     * 
+     * @see android.content.ContentProvider
+     * @see android.widget.CursorAdapter
+     * @see #loadAdapter(android.content.Context, int, Object[]) 
+     */
+    public static CursorAdapter loadCursorAdapter(Context context, int id, String uri,
+            Object... parameters) {
+
+        XmlCursorAdapter adapter = (XmlCursorAdapter) loadAdapter(context, id, ADAPTER_CURSOR,
+                parameters);
+
+        if (uri != null) {
+            adapter.setUri(uri);
+        }
+        adapter.load();
+
+        return adapter;
+    }
+    
+    /**
+     * <p>Loads the {@link android.widget.CursorAdapter} defined in the specified
+     * XML resource. The content of the adapter is loaded from the specified cursor.
+     * You are responsible for managing the supplied cursor.</p>
+     * 
+     * <p>The format of the XML definition of the cursor adapter is documented at
+     * the top of this page.</p>
+     * 
+     * @param context The context to load the XML resource from.
+     * @param id The identifier of the XML resource declaring the adapter.
+     * @param cursor The cursor containing the data for the adapter.
+     * @param parameters Optional parameters to pass to the CursorAdapter, used
+     *        to substitute values in the selection expression.
+     * 
+     * @return A {@link android.widget.CursorAdapter}
+     * 
+     * @throws IllegalArgumentException If the XML resource does not contain
+     *         a valid &lt;cursor-adapter /&gt; definition.
+     * 
+     * @see android.content.ContentProvider
+     * @see android.widget.CursorAdapter
+     * @see android.database.Cursor
+     * @see #loadAdapter(android.content.Context, int, Object[]) 
+     */
+    public static CursorAdapter loadCursorAdapter(Context context, int id, Cursor cursor,
+            Object... parameters) {
+
+        XmlCursorAdapter adapter = (XmlCursorAdapter) loadAdapter(context, id, ADAPTER_CURSOR,
+                parameters);
+
+        if (cursor != null) {
+            adapter.changeCursor(cursor);
+        }
+
+        return adapter;
+    }
+
+    /**
+     * <p>Loads the adapter defined in the specified XML resource. The XML definition of
+     * the adapter must follow the format definition of one of the supported adapter
+     * types described at the top of this page.</p>
+     * 
+     * <p><strong>Note:</strong> If the loaded adapter is a {@link android.widget.CursorAdapter}
+     * and the supplied {@link android.content.Context} is an {@link android.app.Activity},
+     * the cursor returned by the content provider will be automatically managed. Otherwise,
+     * you are responsible for managing the cursor yourself.</p>
+     * 
+     * @param context The context to load the XML resource from.
+     * @param id The identifier of the XML resource declaring the adapter.
+     * @param parameters Optional parameters to pass to the adapter.
+     *  
+     * @return An adapter instance.
+     * 
+     * @see #loadCursorAdapter(android.content.Context, int, android.database.Cursor, Object[]) 
+     * @see #loadCursorAdapter(android.content.Context, int, String, Object[]) 
+     */
+    public static BaseAdapter loadAdapter(Context context, int id, Object... parameters) {
+        final BaseAdapter adapter = loadAdapter(context, id, null, parameters);
+        if (adapter instanceof ManagedAdapter) {
+            ((ManagedAdapter) adapter).load();
+        }
+        return adapter;
+    }
+
+    /**
+     * Loads an adapter from the specified XML resource. The optional assertName can
+     * be used to exit early if the adapter defined in the XML resource is not of the
+     * expected type.
+     * 
+     * @param context The context to associate with the adapter.
+     * @param id The resource id of the XML document defining the adapter.
+     * @param assertName The mandatory name of the adapter in the XML document.
+     *        Ignored if null.
+     * @param parameters Optional parameters passed to the adapter.
+     * 
+     * @return An instance of {@link android.widget.BaseAdapter}.
+     */
+    private static BaseAdapter loadAdapter(Context context, int id, String assertName,
+                Object... parameters) {
+
+        XmlResourceParser parser = null;
+        try {
+            parser = context.getResources().getXml(id);
+            return createAdapterFromXml(context, parser, Xml.asAttributeSet(parser),
+                    id, parameters, assertName);
+        } catch (XmlPullParserException ex) {
+            Resources.NotFoundException rnf = new Resources.NotFoundException(
+                    "Can't load adapter resource ID " +
+                            context.getResources().getResourceEntryName(id));
+            rnf.initCause(ex);
+            throw rnf;
+        } catch (IOException ex) {
+            Resources.NotFoundException rnf = new Resources.NotFoundException(
+                    "Can't load adapter resource ID " +
+                            context.getResources().getResourceEntryName(id));
+            rnf.initCause(ex);
+            throw rnf;
+        } finally {
+            if (parser != null) parser.close();
+        }
+    }
+
+    /**
+     * Generates an adapter using the specified XML parser. This method is responsible
+     * for choosing the type of the adapter to create based on the content of the
+     * XML parser.
+     * 
+     * This method will generate an {@link IllegalArgumentException} if
+     * <code>assertName</code> is not null and does not match the root tag of the XML
+     * document. 
+     */
+    private static BaseAdapter createAdapterFromXml(Context c,
+            XmlPullParser parser, AttributeSet attrs, int id, Object[] parameters,
+            String assertName) throws XmlPullParserException, IOException {
+        
+        BaseAdapter adapter = null;
+ 
+        // Make sure we are on a start tag.
+        int type;
+        int depth = parser.getDepth();
+
+        while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) &&
+                type != XmlPullParser.END_DOCUMENT) {
+
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            String name = parser.getName();
+            if (assertName != null && !assertName.equals(name)) {
+                throw new IllegalArgumentException("The adapter defined in " +
+                        c.getResources().getResourceEntryName(id) + " must be a <" + name + " />");
+            }
+    
+            if (ADAPTER_CURSOR.equals(name)) {
+                adapter = createCursorAdapter(c, parser, attrs, id, parameters);
+            } else {
+                throw new IllegalArgumentException("Unknown adapter name " + parser.getName() +
+                        " in " + c.getResources().getResourceEntryName(id));
+            }
+        }
+    
+        return adapter;
+
+    }
+
+    /**
+     * Creates an XmlCursorAdapter using an XmlCursorAdapterParser.
+     */
+    private static XmlCursorAdapter createCursorAdapter(Context c, XmlPullParser parser,
+            AttributeSet attrs, int id, Object[] parameters)
+            throws IOException, XmlPullParserException {
+
+        return new XmlCursorAdapterParser(c, parser, attrs, id).parse(parameters);
+    }
+
+    /**
+     * Parser that can generate XmlCursorAdapter instances. This parser is responsible for
+     * handling all the attributes and child nodes for a &lt;cursor-adapter /&gt;.
+     */
+    private static class XmlCursorAdapterParser {
+        private static final String ADAPTER_CURSOR_BIND = "bind";
+        private static final String ADAPTER_CURSOR_SELECT = "select";
+        private static final String ADAPTER_CURSOR_AS_STRING = "string";
+        private static final String ADAPTER_CURSOR_AS_IMAGE = "image";
+        private static final String ADAPTER_CURSOR_AS_IMAGE_URI = "image-uri";
+        private static final String ADAPTER_CURSOR_AS_DRAWABLE = "drawable";
+        private static final String ADAPTER_CURSOR_MAP = "map";
+        private static final String ADAPTER_CURSOR_TRANSFORM = "transform";
+
+        private final Context mContext;
+        private final XmlPullParser mParser;
+        private final AttributeSet mAttrs;
+        private final int mId;
+
+        private final HashMap<String, CursorBinder> mBinders;
+        private final ArrayList<String> mFrom;
+        private final ArrayList<Integer> mTo;
+        private final CursorTransformation mIdentity;
+        private final Resources mResources;
+
+        public XmlCursorAdapterParser(Context c, XmlPullParser parser, AttributeSet attrs, int id) {
+            mContext = c;
+            mParser = parser;
+            mAttrs = attrs;
+            mId = id;
+
+            mResources = mContext.getResources();
+            mBinders = new HashMap<String, CursorBinder>();
+            mFrom = new ArrayList<String>();
+            mTo = new ArrayList<Integer>();
+            mIdentity = new IdentityTransformation(mContext);            
+        }
+
+        public XmlCursorAdapter parse(Object[] parameters)
+                throws IOException, XmlPullParserException {
+
+            Resources resources = mResources;
+            TypedArray a = resources.obtainAttributes(mAttrs, styleable.CursorAdapter);
+            
+            String uri = a.getString(styleable.CursorAdapter_uri);
+            String selection = a.getString(styleable.CursorAdapter_selection);
+            String sortOrder = a.getString(styleable.CursorAdapter_sortOrder);
+            int layout = a.getResourceId(styleable.CursorAdapter_layout, 0);
+            if (layout == 0) {
+                throw new IllegalArgumentException("The layout specified in " +
+                        resources.getResourceEntryName(mId) + " does not exist");
+            }
+
+            a.recycle();
+    
+            XmlPullParser parser = mParser;
+            int type;
+            int depth = parser.getDepth();
+    
+            while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) &&
+                    type != XmlPullParser.END_DOCUMENT) {
+    
+                if (type != XmlPullParser.START_TAG) {
+                    continue;
+                }
+                
+                String name = parser.getName();
+                
+                if (ADAPTER_CURSOR_BIND.equals(name)) {
+                    parseBindTag();
+                } else if (ADAPTER_CURSOR_SELECT.equals(name)) {
+                    parseSelectTag();
+                } else {
+                    throw new RuntimeException("Unknown tag name " + parser.getName() + " in " +
+                        resources.getResourceEntryName(mId));
+                }
+            }
+    
+            String[] fromArray = mFrom.toArray(new String[mFrom.size()]);
+            int[] toArray = new int[mTo.size()];
+            for (int i = 0; i < toArray.length; i++) {
+                toArray[i] = mTo.get(i);
+            }
+
+            String[] selectionArgs = null;
+            if (parameters != null) {
+                selectionArgs = new String[parameters.length];
+                for (int i = 0; i < selectionArgs.length; i++) {
+                    selectionArgs[i] = (String) parameters[i];
+                }
+            }
+
+            return new XmlCursorAdapter(mContext, layout, uri, fromArray, toArray, selection,
+                    selectionArgs, sortOrder, mBinders);
+        }
+    
+        private void parseSelectTag() {
+            TypedArray a = mResources.obtainAttributes(mAttrs, styleable.CursorAdapter_SelectItem);
+    
+            String fromName = a.getString(styleable.CursorAdapter_SelectItem_column);
+            if (fromName == null) {
+                throw new IllegalArgumentException("A select item in " +
+                    mResources.getResourceEntryName(mId) + " does not have a 'column' attribute");
+            }
+            
+            a.recycle();
+            
+            mFrom.add(fromName);
+            mTo.add(View.NO_ID);
+        }
+    
+        private void parseBindTag() throws IOException, XmlPullParserException {
+            Resources resources = mResources;
+            TypedArray a = resources.obtainAttributes(mAttrs, styleable.CursorAdapter_BindItem);
+    
+            String fromName = a.getString(styleable.CursorAdapter_BindItem_from);
+            if (fromName == null) {
+                throw new IllegalArgumentException("A bind item in " +
+                    resources.getResourceEntryName(mId) + " does not have a 'from' attribute");
+            }
+    
+            int toName = a.getResourceId(styleable.CursorAdapter_BindItem_to, 0);
+            if (toName == 0) {
+                throw new IllegalArgumentException("A bind item in " +
+                    resources.getResourceEntryName(mId) + " does not have a 'to' attribute");
+            }
+            
+            String asType = a.getString(styleable.CursorAdapter_BindItem_as);
+            if (asType == null) {
+                throw new IllegalArgumentException("A bind item in " +
+                    resources.getResourceEntryName(mId) + " does not have an 'as' attribute");
+            }
+    
+            mFrom.add(fromName);
+            mTo.add(toName);
+            mBinders.put(fromName, findBinder(asType));
+    
+            a.recycle();
+        }
+    
+        private CursorBinder findBinder(String type) throws IOException, XmlPullParserException {
+            final XmlPullParser parser = mParser;
+            final Context context = mContext;
+            CursorTransformation transformation = mIdentity;
+    
+            int tagType;
+            int depth = parser.getDepth();
+            
+            final boolean isDrawable = ADAPTER_CURSOR_AS_DRAWABLE.equals(type);            
+    
+            while (((tagType = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+                    && tagType != XmlPullParser.END_DOCUMENT) {
+    
+                if (tagType != XmlPullParser.START_TAG) {
+                    continue;
+                }
+
+                String name = parser.getName();
+                
+                if (ADAPTER_CURSOR_TRANSFORM.equals(name)) {
+                    transformation = findTransformation();
+                } else if (ADAPTER_CURSOR_MAP.equals(name)) {
+                    if (!(transformation instanceof MapTransformation)) {
+                        transformation = new MapTransformation(context);
+                    }
+                    findMap(((MapTransformation) transformation), isDrawable);
+                } else {
+                    throw new RuntimeException("Unknown tag name " + parser.getName() + " in " +
+                        context.getResources().getResourceEntryName(mId));
+                }
+            }
+            
+            if (ADAPTER_CURSOR_AS_STRING.equals(type)) {
+                return new StringBinder(context, transformation);
+            } else if (ADAPTER_CURSOR_AS_IMAGE.equals(type)) {
+                return new ImageBinder(context, transformation);            
+            } else if (ADAPTER_CURSOR_AS_IMAGE_URI.equals(type)) {
+                return new ImageUriBinder(context, transformation);
+            } else if (isDrawable) {
+                return new DrawableBinder(context, transformation);
+            } else {
+                return createBinder(type, transformation);
+            }
+        }
+
+        private CursorBinder createBinder(String type, CursorTransformation transformation) {
+            if (mContext.isRestricted()) return null;
+
+            try {
+                final Class<?> klass = Class.forName(type, true, mContext.getClassLoader());
+                if (CursorBinder.class.isAssignableFrom(klass)) {
+                    final Constructor<?> c = klass.getDeclaredConstructor(
+                            Context.class, CursorTransformation.class);
+                    return (CursorBinder) c.newInstance(mContext, transformation);
+                }
+            } catch (ClassNotFoundException e) {
+                throw new IllegalArgumentException("Cannot instanciate binder type in " +
+                    mContext.getResources().getResourceEntryName(mId) + ": " + type, e);
+            } catch (NoSuchMethodException e) {
+                throw new IllegalArgumentException("Cannot instanciate binder type in " +
+                    mContext.getResources().getResourceEntryName(mId) + ": " + type, e);
+            } catch (InvocationTargetException e) {
+                throw new IllegalArgumentException("Cannot instanciate binder type in " +
+                    mContext.getResources().getResourceEntryName(mId) + ": " + type, e);
+            } catch (InstantiationException e) {
+                throw new IllegalArgumentException("Cannot instanciate binder type in " +
+                    mContext.getResources().getResourceEntryName(mId) + ": " + type, e);
+            } catch (IllegalAccessException e) {
+                throw new IllegalArgumentException("Cannot instanciate binder type in " +
+                    mContext.getResources().getResourceEntryName(mId) + ": " + type, e);
+            }
+
+            return null;
+        }
+
+        private void findMap(MapTransformation transformation, boolean drawable) {
+            Resources resources = mResources;
+
+            TypedArray a = resources.obtainAttributes(mAttrs, styleable.CursorAdapter_MapItem);
+
+            String from = a.getString(styleable.CursorAdapter_MapItem_fromValue);
+            if (from == null) {
+                throw new IllegalArgumentException("A map item in " +
+                    resources.getResourceEntryName(mId) + " does not have a 'fromValue' attribute");
+            }
+
+            if (!drawable) {
+                String to = a.getString(styleable.CursorAdapter_MapItem_toValue);
+                if (to == null) {
+                    throw new IllegalArgumentException("A map item in " +
+                        resources.getResourceEntryName(mId) + " does not have a 'toValue' attribute");
+                }
+                transformation.addStringMapping(from, to);
+            } else {
+                int to = a.getResourceId(styleable.CursorAdapter_MapItem_toValue, 0);
+                if (to == 0) {
+                    throw new IllegalArgumentException("A map item in " +
+                        resources.getResourceEntryName(mId) + " does not have a 'toValue' attribute");
+                }
+                transformation.addResourceMapping(from, to);
+            }
+
+            a.recycle();
+        }
+
+        private CursorTransformation findTransformation() {
+            Resources resources = mResources;
+            CursorTransformation transformation = null;
+            TypedArray a = resources.obtainAttributes(mAttrs, styleable.CursorAdapter_TransformItem);
+            
+            String className = a.getString(styleable.CursorAdapter_TransformItem_withClass);
+            if (className == null) {
+                String expression = a.getString(
+                        styleable.CursorAdapter_TransformItem_withExpression);
+                transformation = createExpressionTransformation(expression);
+            } else if (!mContext.isRestricted()) {
+                try {
+                    final Class<?> klass = Class.forName(className, true, mContext.getClassLoader());
+                    if (CursorTransformation.class.isAssignableFrom(klass)) {
+                        final Constructor<?> c = klass.getDeclaredConstructor(Context.class);
+                        transformation = (CursorTransformation) c.newInstance(mContext);
+                    }
+                } catch (ClassNotFoundException e) {
+                    throw new IllegalArgumentException("Cannot instanciate transform type in " +
+                        mContext.getResources().getResourceEntryName(mId) + ": " + className, e);
+                } catch (NoSuchMethodException e) {
+                    throw new IllegalArgumentException("Cannot instanciate transform type in " +
+                        mContext.getResources().getResourceEntryName(mId) + ": " + className, e);
+                } catch (InvocationTargetException e) {
+                    throw new IllegalArgumentException("Cannot instanciate transform type in " +
+                        mContext.getResources().getResourceEntryName(mId) + ": " + className, e);
+                } catch (InstantiationException e) {
+                    throw new IllegalArgumentException("Cannot instanciate transform type in " +
+                        mContext.getResources().getResourceEntryName(mId) + ": " + className, e);
+                } catch (IllegalAccessException e) {
+                    throw new IllegalArgumentException("Cannot instanciate transform type in " +
+                        mContext.getResources().getResourceEntryName(mId) + ": " + className, e);
+                }
+            }
+
+            a.recycle();
+            
+            if (transformation == null) {
+                throw new IllegalArgumentException("A transform item in " +
+                    resources.getResourceEntryName(mId) + " must have a 'withClass' or " +
+                    "'withExpression' attribute");
+            }
+
+            return transformation;
+        }
+
+        private CursorTransformation createExpressionTransformation(String expression) {
+            return new ExpressionTransformation(mContext, expression);
+        }
+    }
+
+    /**
+     * Interface used by adapters that require to be loaded after creation.
+     */
+    private static interface ManagedAdapter {
+        /**
+         * Loads the content of the adapter, asynchronously.
+         */
+        void load();
+    }
+
+    /**
+     * Implementation of a Cursor adapter defined in XML. This class is a thin wrapper
+     * of a SimpleCursorAdapter. The main difference is the ability to handle CursorBinders.
+     */
+    private static class XmlCursorAdapter extends SimpleCursorAdapter implements ManagedAdapter {
+        private final Context mContext;
+        private String mUri;
+        private final String mSelection;
+        private final String[] mSelectionArgs;
+        private final String mSortOrder;
+        private final String[] mColumns;
+        private final CursorBinder[] mBinders;
+        private AsyncTask<Void,Void,Cursor> mLoadTask;
+
+        XmlCursorAdapter(Context context, int layout, String uri, String[] from, int[] to,
+                String selection, String[] selectionArgs, String sortOrder,
+                HashMap<String, CursorBinder> binders) {
+
+            super(context, layout, null, from, to);
+            mContext = context;
+            mUri = uri;
+            mSelection = selection;
+            mSelectionArgs = selectionArgs;
+            mSortOrder = sortOrder;
+            mColumns = new String[from.length + 1];
+            // This is mandatory in CursorAdapter
+            mColumns[0] = "_id";
+            System.arraycopy(from, 0, mColumns, 1, from.length);
+
+            CursorBinder basic = new StringBinder(context, new IdentityTransformation(context));
+            final int count = from.length;
+            mBinders = new CursorBinder[count];
+
+            for (int i = 0; i < count; i++) {
+                CursorBinder binder = binders.get(from[i]);
+                if (binder == null) binder = basic;
+                mBinders[i] = binder;
+            }
+        }
+        
+        @Override
+        public void bindView(View view, Context context, Cursor cursor) {
+            final int count = mTo.length;
+            final int[] from = mFrom;
+            final int[] to = mTo;
+            final CursorBinder[] binders = mBinders;
+    
+            for (int i = 0; i < count; i++) {
+                final View v = view.findViewById(to[i]);
+                if (v != null) {
+                    binders[i].bind(v, cursor, from[i]);
+                }
+            }
+        }
+        
+        public void load() {
+            if (mUri != null) {
+                mLoadTask = new QueryTask().execute();
+            }
+        }
+
+        void setUri(String uri) {
+            mUri = uri;
+        }
+
+        @Override
+        public void changeCursor(Cursor c) {
+            if (mLoadTask != null && mLoadTask.getStatus() != QueryTask.Status.FINISHED) {
+                mLoadTask.cancel(true);
+                mLoadTask = null;
+            }
+            super.changeCursor(c);
+        }
+
+        class QueryTask extends AsyncTask<Void, Void, Cursor> {
+            @Override
+            protected Cursor doInBackground(Void... params) {
+                if (mContext instanceof Activity) {
+                    return ((Activity) mContext).managedQuery(
+                            Uri.parse(mUri), mColumns, mSelection, mSelectionArgs, mSortOrder);
+                } else {
+                    return mContext.getContentResolver().query(
+                            Uri.parse(mUri), mColumns, mSelection, mSelectionArgs, mSortOrder);
+                }
+            }
+
+            @Override
+            protected void onPostExecute(Cursor cursor) {
+                if (!isCancelled()) {
+                    XmlCursorAdapter.super.changeCursor(cursor);
+                }
+            }
+        }
+    }
+
+    /**
+     * Identity transformation, returns the content of the specified column as a String,
+     * without performing any manipulation. This is used when no transformation is specified.
+     */
+    private static class IdentityTransformation extends CursorTransformation {
+        public IdentityTransformation(Context context) {
+            super(context);
+        }
+
+        @Override
+        public String transform(Cursor cursor, int columnIndex) {
+            return cursor.getString(columnIndex);
+        }
+    }
+
+    /**
+     * An expression transformation is a simple template based replacement utility.
+     * In an expression, each segment of the form <code>{(^[}]+)}</code> is replaced
+     * with the value of the column of name $1.
+     */
+    private static class ExpressionTransformation extends CursorTransformation {
+        private final ExpressionNode mFirstNode = new ConstantExpressionNode("");
+        private final StringBuilder mBuilder = new StringBuilder();
+        
+        public ExpressionTransformation(Context context, String expression) {
+            super(context);
+            
+            parse(expression);
+        }
+
+        private void parse(String expression) {
+            ExpressionNode node = mFirstNode;
+            int segmentStart;
+            int count = expression.length();
+
+            for (int i = 0; i < count; i++) {
+                char c = expression.charAt(i);
+                // Start a column name segment
+                segmentStart = i;
+                if (c == '{') {
+                    while (i < count && (c = expression.charAt(i)) != '}') {
+                        i++;
+                    }
+                    // We've reached the end, but the expression didn't close
+                    if (c != '}') {
+                        throw new IllegalStateException("The transform expression contains a " +
+                                "non-closed column name: " +
+                                expression.substring(segmentStart + 1, i));
+                    }
+                    node.next = new ColumnExpressionNode(expression.substring(segmentStart + 1, i));
+                } else {
+                    while (i < count && (c = expression.charAt(i)) != '{') {
+                        i++;
+                    }
+                    node.next = new ConstantExpressionNode(expression.substring(segmentStart, i));
+                    // Rewind if we've reached a column expression
+                    if (c == '{') i--;
+                }
+                node = node.next;
+            }
+        }
+
+        @Override
+        public String transform(Cursor cursor, int columnIndex) {
+            final StringBuilder builder = mBuilder;
+            builder.delete(0, builder.length());
+            
+            ExpressionNode node = mFirstNode;
+            // Skip the first node
+            while ((node = node.next) != null) {
+                builder.append(node.asString(cursor));
+            }
+
+            return builder.toString();
+        }
+        
+        static abstract class ExpressionNode {
+            public ExpressionNode next;
+
+            public abstract String asString(Cursor cursor);
+        }
+        
+        static class ConstantExpressionNode extends ExpressionNode {
+            private final String mConstant;
+
+            ConstantExpressionNode(String constant) {
+                mConstant = constant;
+            }
+
+            @Override
+            public String asString(Cursor cursor) {
+                return mConstant;
+            }
+        }
+        
+        static class ColumnExpressionNode extends ExpressionNode {
+            private final String mColumnName;
+            private Cursor mSignature;
+            private int mColumnIndex = -1;
+
+            ColumnExpressionNode(String columnName) {
+                mColumnName = columnName;
+            }
+
+            @Override
+            public String asString(Cursor cursor) {
+                if (cursor != mSignature || mColumnIndex == -1) {
+                    mColumnIndex = cursor.getColumnIndex(mColumnName);
+                    mSignature = cursor;
+                }
+
+                return cursor.getString(mColumnIndex);
+            }
+        }
+    }
+
+    /**
+     * A map transformation offers a simple mapping between specified String values
+     * to Strings or integers.
+     */
+    private static class MapTransformation extends CursorTransformation {
+        private final HashMap<String, String> mStringMappings;
+        private final HashMap<String, Integer> mResourceMappings;
+
+        public MapTransformation(Context context) {
+            super(context);
+            mStringMappings = new HashMap<String, String>();
+            mResourceMappings = new HashMap<String, Integer>();
+        }
+
+        void addStringMapping(String from, String to) {
+            mStringMappings.put(from, to);
+        }
+
+        void addResourceMapping(String from, int to) {
+            mResourceMappings.put(from, to);
+        }
+
+        @Override
+        public String transform(Cursor cursor, int columnIndex) {
+            final String value = cursor.getString(columnIndex);
+            final String transformed = mStringMappings.get(value);
+            return transformed == null ? value : transformed;
+        }
+
+        @Override
+        public int transformToResource(Cursor cursor, int columnIndex) {
+            final String value = cursor.getString(columnIndex);
+            final Integer transformed = mResourceMappings.get(value);
+            try {
+                return transformed == null ? Integer.parseInt(value) : transformed;
+            } catch (NumberFormatException e) {
+                return 0;
+            }
+        }
+    }
+
+    /**
+     * Binds a String to a TextView.
+     */
+    private static class StringBinder extends CursorBinder {
+        public StringBinder(Context context, CursorTransformation transformation) {
+            super(context, transformation);
+        }
+
+        @Override
+        public boolean bind(View view, Cursor cursor, int columnIndex) {
+            ((TextView) view).setText(mTransformation.transform(cursor, columnIndex));
+            return true;
+        }
+    }
+
+    /**
+     * Binds an image blob to an ImageView.
+     */
+    private static class ImageBinder extends CursorBinder {
+        public ImageBinder(Context context, CursorTransformation transformation) {
+            super(context, transformation);
+        }
+
+        @Override
+        public boolean bind(View view, Cursor cursor, int columnIndex) {
+            final byte[] data = cursor.getBlob(columnIndex);
+            ((ImageView) view).setImageBitmap(BitmapFactory.decodeByteArray(data, 0, data.length));
+            return true;
+        }
+    }
+
+    /**
+     * Binds an image URI to an ImageView.
+     */
+    private static class ImageUriBinder extends CursorBinder {
+        public ImageUriBinder(Context context, CursorTransformation transformation) {
+            super(context, transformation);
+        }
+
+        @Override
+        public boolean bind(View view, Cursor cursor, int columnIndex) {
+            ((ImageView) view).setImageURI(Uri.parse(
+                    mTransformation.transform(cursor, columnIndex)));
+            return true;
+        }
+    }
+
+    /**
+     * Binds a drawable resource identifier to an ImageView.
+     */
+    private static class DrawableBinder extends CursorBinder {
+        public DrawableBinder(Context context, CursorTransformation transformation) {
+            super(context, transformation);
+        }
+
+        @Override
+        public boolean bind(View view, Cursor cursor, int columnIndex) {
+            final int resource = mTransformation.transformToResource(cursor, columnIndex);
+            if (resource == 0) return false;
+
+            ((ImageView) view).setImageResource(resource);
+            return true;
+        }
+    }
+}
diff --git a/core/java/android/widget/CursorAdapter.java b/core/java/android/widget/CursorAdapter.java
index baa6833..6a891fc 100644
--- a/core/java/android/widget/CursorAdapter.java
+++ b/core/java/android/widget/CursorAdapter.java
@@ -80,6 +80,18 @@
     protected FilterQueryProvider mFilterQueryProvider;
 
     /**
+     * If set the adapter will call requery() on the cursor whenever a content change
+     * notification is delivered. Implies {@link #FLAG_REGISTER_CONTENT_OBSERVER}
+     */
+    public static final int FLAG_AUTO_REQUERY = 0x01;
+
+    /**
+     * If set the adapter will register a content observer on the cursor and will call
+     * {@link #onContentChanged()} when a notification comes in.
+     */
+    public static final int FLAG_REGISTER_CONTENT_OBSERVER = 0x02;
+
+    /**
      * Constructor. The adapter will call requery() on the cursor whenever
      * it changes so that the most recent data is always displayed.
      *
@@ -87,7 +99,7 @@
      * @param context The context
      */
     public CursorAdapter(Context context, Cursor c) {
-        init(context, c, true);
+        init(context, c, FLAG_AUTO_REQUERY);
     }
 
     /**
@@ -99,19 +111,43 @@
      *                    data is always displayed.
      */
     public CursorAdapter(Context context, Cursor c, boolean autoRequery) {
-        init(context, c, autoRequery);
+        init(context, c, autoRequery ? FLAG_AUTO_REQUERY : 0);
+    }
+
+    /**
+     * Constructor
+     * @param c The cursor from which to get the data.
+     * @param context The context
+     * @param flags flags used to determine the behavior of the adapter
+     */
+    public CursorAdapter(Context context, Cursor c, int flags) {
+        init(context, c, flags);
     }
 
     protected void init(Context context, Cursor c, boolean autoRequery) {
+        init(context, c, autoRequery ? FLAG_AUTO_REQUERY : 0);
+    }
+
+    protected void init(Context context, Cursor c, int flags) {
+        if ((flags & FLAG_AUTO_REQUERY) == FLAG_AUTO_REQUERY) {
+            flags |= FLAG_REGISTER_CONTENT_OBSERVER;
+            mAutoRequery = true;
+        } else {
+            mAutoRequery = false;
+        }
         boolean cursorPresent = c != null;
-        mAutoRequery = autoRequery;
         mCursor = c;
         mDataValid = cursorPresent;
         mContext = context;
         mRowIDColumn = cursorPresent ? c.getColumnIndexOrThrow("_id") : -1;
-        mChangeObserver = new ChangeObserver();
+        if ((flags & FLAG_REGISTER_CONTENT_OBSERVER) == FLAG_REGISTER_CONTENT_OBSERVER) {
+            mChangeObserver = new ChangeObserver();
+        } else {
+            mChangeObserver = null;
+        }
+
         if (cursorPresent) {
-            c.registerContentObserver(mChangeObserver);
+            if (mChangeObserver != null) c.registerContentObserver(mChangeObserver);
             c.registerDataSetObserver(mDataSetObserver);
         }
     }
@@ -246,13 +282,13 @@
             return;
         }
         if (mCursor != null) {
-            mCursor.unregisterContentObserver(mChangeObserver);
+            if (mChangeObserver != null) mCursor.unregisterContentObserver(mChangeObserver);
             mCursor.unregisterDataSetObserver(mDataSetObserver);
             mCursor.close();
         }
         mCursor = cursor;
         if (cursor != null) {
-            cursor.registerContentObserver(mChangeObserver);
+            if (mChangeObserver != null) cursor.registerContentObserver(mChangeObserver);
             cursor.registerDataSetObserver(mDataSetObserver);
             mRowIDColumn = cursor.getColumnIndexOrThrow("_id");
             mDataValid = true;
diff --git a/core/java/android/widget/SimpleCursorAdapter.java b/core/java/android/widget/SimpleCursorAdapter.java
index 7d3459e..d1c2270 100644
--- a/core/java/android/widget/SimpleCursorAdapter.java
+++ b/core/java/android/widget/SimpleCursorAdapter.java
@@ -62,7 +62,8 @@
     private int mStringConversionColumn = -1;
     private CursorToStringConverter mCursorToStringConverter;
     private ViewBinder mViewBinder;
-    private String[] mOriginalFrom;
+
+    String[] mOriginalFrom;
 
     /**
      * Constructor.
diff --git a/core/java/com/android/internal/app/NetInitiatedActivity.java b/core/java/com/android/internal/app/NetInitiatedActivity.java
index 24818a8..03b0957 100755
--- a/core/java/com/android/internal/app/NetInitiatedActivity.java
+++ b/core/java/com/android/internal/app/NetInitiatedActivity.java
@@ -30,7 +30,6 @@
 import android.widget.Toast;
 import android.util.Log;
 import android.location.LocationManager;
-import com.android.internal.location.GpsLocationProvider;
 import com.android.internal.location.GpsNetInitiatedHandler;
 
 /**
diff --git a/core/java/com/android/internal/widget/DigitalClock.java b/core/java/com/android/internal/widget/DigitalClock.java
index fa47ff6..23e2277 100644
--- a/core/java/com/android/internal/widget/DigitalClock.java
+++ b/core/java/com/android/internal/widget/DigitalClock.java
@@ -30,7 +30,7 @@
 import android.text.format.DateFormat;
 import android.util.AttributeSet;
 import android.view.View;
-import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
 import android.widget.TextView;
 
 import java.text.DateFormatSymbols;
@@ -39,7 +39,7 @@
 /**
  * Displays the time
  */
-public class DigitalClock extends LinearLayout {
+public class DigitalClock extends RelativeLayout {
 
     private final static String M12 = "h:mm";
     private final static String M24 = "kk:mm";
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 85d1a6f..6d1a414 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -121,7 +121,6 @@
 	android_server_BluetoothA2dpService.cpp \
 	android_message_digest_sha1.cpp \
 	android_ddm_DdmHandleNativeHeap.cpp \
-	android_location_GpsLocationProvider.cpp \
 	com_android_internal_os_ZygoteInit.cpp \
 	com_android_internal_graphics_NativeUtils.cpp \
 	android_backup_BackupDataInput.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 7f8e854..c9e5bdc 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -154,7 +154,6 @@
 extern int register_android_server_BluetoothA2dpService(JNIEnv* env);
 extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
 extern int register_com_android_internal_os_ZygoteInit(JNIEnv* env);
-extern int register_android_location_GpsLocationProvider(JNIEnv* env);
 extern int register_android_backup_BackupDataInput(JNIEnv *env);
 extern int register_android_backup_BackupDataOutput(JNIEnv *env);
 extern int register_android_backup_FileBackupHelperBase(JNIEnv *env);
@@ -1267,7 +1266,6 @@
     REG_JNI(register_android_server_BluetoothA2dpService),
     REG_JNI(register_android_message_digest_sha1),
     REG_JNI(register_android_ddm_DdmHandleNativeHeap),
-    REG_JNI(register_android_location_GpsLocationProvider),
     REG_JNI(register_android_backup_BackupDataInput),
     REG_JNI(register_android_backup_BackupDataOutput),
     REG_JNI(register_android_backup_FileBackupHelperBase),
diff --git a/core/res/res/drawable/ic_btn_back.png b/core/res/res/drawable/ic_btn_back.png
new file mode 100644
index 0000000..c9bff4c
--- /dev/null
+++ b/core/res/res/drawable/ic_btn_back.png
Binary files differ
diff --git a/core/res/res/drawable/ic_btn_next.png b/core/res/res/drawable/ic_btn_next.png
new file mode 100755
index 0000000..c6cf436
--- /dev/null
+++ b/core/res/res/drawable/ic_btn_next.png
Binary files differ
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml
index b404955..a4b2357 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml
@@ -41,20 +41,21 @@
         android:ellipsize="marquee"
         android:gravity="right|bottom"
         android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textSize="22sp"
         />
 
-    <!-- emergency call button shown when sim is missing or PUKd -->
-    <Button
-        android:id="@+id/emergencyCallButton"
+    <!-- "emergency calls only" shown when sim is missing or PUKd -->
+    <TextView
+        android:id="@+id/emergencyCallText"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_alignParentTop="true"
+        android:layout_below="@id/carrier"
         android:layout_alignParentRight="true"
-        android:layout_marginTop="10dip"
+        android:layout_marginTop="0dip"
         android:layout_marginRight="8dip"
-        android:drawableLeft="@drawable/ic_emergency"
-        style="@style/Widget.Button.Transparent"
-        android:drawablePadding="8dip"
+        android:text="@string/emergency_calls_only"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:textColor="@color/white"
        />
 
     <!-- time and date -->
@@ -64,6 +65,7 @@
         android:layout_below="@id/carrier"
         android:layout_marginTop="52dip"
         android:layout_marginLeft="20dip"
+        android:layout_marginBottom="8dip"
         >
 
         <TextView android:id="@+id/timeDisplay"
@@ -71,7 +73,6 @@
             android:layout_height="wrap_content"
             android:singleLine="true"
             android:ellipsize="none"
-            android:gravity="bottom"
             android:textSize="72sp"
             android:textAppearance="?android:attr/textAppearanceMedium"
             android:shadowColor="#C0000000"
@@ -84,8 +85,9 @@
 
         <TextView android:id="@+id/am_pm"
             android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:gravity="bottom"
+            android:layout_height="wrap_content"
+            android:layout_toRightOf="@id/timeDisplay"
+            android:layout_alignBaseline="@id/timeDisplay"
             android:singleLine="true"
             android:ellipsize="none"
             android:textSize="22sp"
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
index 6ee659c..e1c9772 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
@@ -46,18 +46,19 @@
             android:ellipsize="marquee"
             android:gravity="right|bottom"
             android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textSize="22sp"
             />
 
-        <!-- emergency call button shown when sim is missing or PUKd -->
-        <Button
-            android:id="@+id/emergencyCallButton"
+        <!-- "emergency calls only" shown when sim is missing or PUKd -->
+        <TextView
+            android:id="@+id/emergencyCallText"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_alignParentTop="true"
             android:layout_marginTop="20dip"
-            android:drawableLeft="@drawable/ic_emergency"
-            style="@style/Widget.Button.Transparent"
-            android:drawablePadding="8dip"
+            android:text="@string/emergency_calls_only"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textColor="@color/white"
            />
 
         <com.android.internal.widget.DigitalClock android:id="@+id/time"
@@ -65,12 +66,12 @@
             android:layout_height="wrap_content"
             android:layout_below="@id/carrier"
             android:layout_marginTop="56dip"
+            android:layout_marginBottom="8dip"
             >
 
             <TextView android:id="@+id/timeDisplay"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:gravity="bottom"
                 android:singleLine="true"
                 android:ellipsize="none"
                 android:textSize="72sp"
@@ -85,8 +86,9 @@
 
             <TextView android:id="@+id/am_pm"
                 android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:gravity="bottom"
+                android:layout_height="wrap_content"
+                android:layout_toRightOf="@id/timeDisplay"
+                android:layout_alignBaseline="@id/timeDisplay"
                 android:singleLine="true"
                 android:ellipsize="none"
                 android:textSize="22sp"
diff --git a/core/res/res/layout/keyguard_screen_unlock_landscape.xml b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
index c1b406f..83381a1 100644
--- a/core/res/res/layout/keyguard_screen_unlock_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
@@ -58,18 +58,19 @@
             android:ellipsize="marquee"
             android:gravity="right|bottom"
             />
+
         <com.android.internal.widget.DigitalClock android:id="@+id/time"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_alignParentTop="true"
             android:layout_alignParentLeft="true"
             android:layout_marginTop="8dip"
+            android:layout_marginBottom="8dip"
             >
 
             <TextView android:id="@+id/timeDisplay"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:gravity="bottom"
                 android:singleLine="true"
                 android:ellipsize="none"
                 android:textSize="72sp"
@@ -84,8 +85,9 @@
 
             <TextView android:id="@+id/am_pm"
                 android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:gravity="bottom"
+                android:layout_height="wrap_content"
+                android:layout_toRightOf="@id/timeDisplay"
+                android:layout_alignBaseline="@id/timeDisplay"
                 android:singleLine="true"
                 android:ellipsize="none"
                 android:textSize="22sp"
diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
index 16cd48c..97c4ae9 100644
--- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
@@ -55,12 +55,12 @@
             android:layout_alignParentTop="true"
             android:layout_marginTop="15dip"
             android:layout_marginLeft="20dip"
+            android:layout_marginBottom="8dip"
             >
 
             <TextView android:id="@+id/timeDisplay"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:gravity="bottom"
                 android:singleLine="true"
                 android:ellipsize="none"
                 android:textSize="56sp"
@@ -74,8 +74,9 @@
 
             <TextView android:id="@+id/am_pm"
                 android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:gravity="bottom"
+                android:layout_height="wrap_content"
+                android:layout_toRightOf="@id/timeDisplay"
+                android:layout_alignBaseline="@id/timeDisplay"
                 android:singleLine="true"
                 android:ellipsize="none"
                 android:textSize="18sp"
diff --git a/core/res/res/layout/preference_list_content.xml b/core/res/res/layout/preference_list_content.xml
index 8f86981..844d338 100644
--- a/core/res/res/layout/preference_list_content.xml
+++ b/core/res/res/layout/preference_list_content.xml
@@ -4,22 +4,58 @@
 **
 ** Copyright 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 
+** 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 
+**     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 
+** 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.
 */
 -->
-<ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/list"
-    android:layout_width="match_parent" 
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
     android:layout_height="match_parent"
-    android:drawSelectorOnTop="false"
-    android:scrollbarAlwaysDrawVerticalTrack="true"
+    android:layout_width="match_parent">
+
+    <ListView android:id="@android:id/list"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:layout_weight="1"
+        android:drawSelectorOnTop="false"
+        android:scrollbarAlwaysDrawVerticalTrack="true"
     />
+
+    <RelativeLayout android:id="@+id/button_bar"
+        android:layout_height="wrap_content"
+        android:layout_width="fill_parent"
+        android:layout_weight="0"
+        android:background="@android:drawable/bottom_bar"
+        android:visibility="gone">
+
+        <Button android:id="@+id/back_button"
+            android:layout_width="150dip"
+            android:layout_height="wrap_content"
+            android:layout_margin="5dip"
+            android:layout_alignParentLeft="true"
+            android:drawableLeft="@drawable/ic_btn_back"
+            android:drawablePadding="3dip"
+            android:text="@string/back_button_label"
+        />
+
+        <Button android:id="@+id/next_button"
+            android:layout_width="150dip"
+            android:layout_height="wrap_content"
+            android:layout_margin="5dip"
+            android:layout_alignParentRight="true"
+            android:drawableRight="@drawable/ic_btn_next"
+            android:drawablePadding="3dip"
+            android:text="@string/next_button_label"
+        />
+    </RelativeLayout>
+</LinearLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 16b241b..2cfba28 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1516,6 +1516,8 @@
              will use only the number of items in the adapter and the number of items visible
              on screen to determine the scrollbar's properties. -->
         <attr name="smoothScrollbar" format="boolean" />
+        <!-- A reference to an XML description of the adapter to attach to the list. -->
+        <attr name="adapter" format="reference" />
     </declare-styleable>
     <declare-styleable name="AbsSpinner">
         <!-- Reference to an array resource that will populate the Spinner.  For static content,
@@ -3631,5 +3633,68 @@
     <declare-styleable name="RecognitionService">
         <attr name="settingsActivity" />
     </declare-styleable>
+    
+    <!-- =============================== -->
+    <!-- Adapters attributes             -->
+    <!-- =============================== -->
+    <eat-comment />
+    
+    <!-- Adapter used to bind cursors. -->
+    <declare-styleable name="CursorAdapter">
+        <!-- URI to get the cursor from. Optional. -->
+        <attr name="uri" format="string" />
+        <!-- Selection statement for the query. Optional. -->
+        <attr name="selection" format="string" />
+        <!-- Sort order statement for the query. Optional. -->
+        <attr name="sortOrder" format="string" />
+        <!-- Layout resource used to display each row from the cursor. Mandatory. -->
+        <attr name="layout" />
+    </declare-styleable>
+    
+    <!-- Attributes used in bind items for XML cursor adapters. -->
+    <declare-styleable name="CursorAdapter_BindItem">
+        <!-- The name of the column to bind from. Mandatory. -->
+        <attr name="from" format="string" />
+        <!-- The resource id of the view to bind to. Mandatory. -->
+        <attr name="to" format="reference" />
+        <!-- The type of binding. If this value is not specified, the type will be
+             inferred from the type of the "to" target view. Mandatory.
+             
+             The type can be one of:
+             <ul>
+             <li>string, The content of the column is interpreted as a string.</li>
+             <li>image, The content of the column is interpreted as a blob describing an image.</li>
+             <li>image-uri, The content of the column is interpreted as a URI to an image.</li>
+             <li>drawable, The content of the column is interpreted as a resource id to a drawable.</li>
+             <li>A fully qualified class name, corresponding to an implementation of
+                 android.widget.Adapters.CursorBinder.</li>
+             </ul>
+         -->
+        <attr name="as" format="string" />
+    </declare-styleable>
+    
+    <!-- Attributes used in select items for XML cursor adapters. -->
+    <declare-styleable name="CursorAdapter_SelectItem">
+        <!-- The name of the column to select. Mandatory. -->
+        <attr name="column" format="string" />
+    </declare-styleable>
+
+    <!-- Attributes used to map values to new values in XML cursor adapters' bind items. -->
+    <declare-styleable name="CursorAdapter_MapItem">
+        <!-- The original value from the column. Mandatory. -->
+        <attr name="fromValue" format="string" />
+        <!-- The new value from the column. Mandatory. -->
+        <attr name="toValue" format="string" />
+    </declare-styleable>
+    
+    <!-- Attributes used to map values to new values in XML cursor adapters' bind items. -->
+    <declare-styleable name="CursorAdapter_TransformItem">
+        <!-- The transformation expression. Mandatory if "withClass" is not specified. -->
+        <attr name="withExpression" format="string" />
+        <!-- The transformation class, an implementation of
+             android.widget.Adapters.CursorTransformation. Mandatory if "withExpression"
+             is not specified. -->
+        <attr name="withClass" format="string" />
+    </declare-styleable>
 
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 98c3a0a..5678b1b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1238,5 +1238,22 @@
   <public type="id" name="custom" id="0x0102002b" />
     
   <public type="anim" name="cycle_interpolator" id="0x010a000c" />
+    
+<!-- ===============================================================
+     Resources proposed for Gingerbread.
+     =============================================================== -->
+  <eat-comment />
+  <public type="attr" name="adapter" id="0x010102be" />
+  <public type="attr" name="selection" id="0x010102bf" />
+  <public type="attr" name="sortOrder" id="0x010102c0" />
+  <public type="attr" name="uri" id="0x010102c1" />
+  <public type="attr" name="from" id="0x010102c2" />
+  <public type="attr" name="to" id="0x010102c3" />
+  <public type="attr" name="as" id="0x010102c4" />
+  <public type="attr" name="fromValue" id="0x010102c5" />
+  <public type="attr" name="toValue" id="0x010102c6" />
+  <public type="attr" name="column" id="0x010102c7" />
+  <public type="attr" name="withExpression" id="0x010102c8" />
+  <public type="attr" name="withClass" id="0x010102c9" />
 
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index bf7425f..f09e8e85 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2257,4 +2257,8 @@
     <!-- Shown when the device is tethered -->
     <string name="tethered_notification_title">Tethering active</string>
     <string name="tethered_notification_message">Touch to configure</string>
+
+    <!--  Strings for possible PreferenceActivity Back/Next buttons -->
+    <string name="back_button_label">Back</string>
+    <string name="next_button_label">Next</string>
 </resources>
diff --git a/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java b/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
index 8e7e63e..fb0f0c1 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
@@ -22,7 +22,7 @@
 import junit.framework.TestCase;
 
 /**
- * Tests StaticLayout bidi implementation.
+ * Quick check of native bidi implementation.
  */
 public class StaticLayoutBidiTest extends TestCase {
     
@@ -41,73 +41,47 @@
     
     //@SmallTest
     public void testAllLtr() {
-        expectBidi(REQ_DL, "a test", "000000", L);
+        expectNativeBidi(REQ_DL, "a test", "000000", L);
     }
     
     //@SmallTest
     public void testLtrRtl() {
-        expectBidi(REQ_DL, "abc " + ALEF + BET + GIMEL, "0000111", L);
+        expectNativeBidi(REQ_DL, "abc " + ALEF + BET + GIMEL, "0000111", L);
     }
     
     //@SmallTest
     public void testAllRtl() {
-        expectBidi(REQ_DL, ALEF + SP + ALEF + BET + GIMEL + DALET, "111111", R);
+        expectNativeBidi(REQ_DL, ALEF + SP + ALEF + BET + GIMEL + DALET, "111111", R);
     }
     
     //@SmallTest
     public void testRtlLtr() {
-        expectBidi(REQ_DL,  ALEF + BET + GIMEL + " abc", "1111000", R);
+        expectNativeBidi(REQ_DL,  ALEF + BET + GIMEL + " abc", "1111222", R);
     }
     
     //@SmallTest
     public void testRAllLtr() {
-        expectBidi(REQ_R, "a test", "000000", R);
+        expectNativeBidi(REQ_R, "a test", "222222", R);
     }
     
     //@SmallTest
     public void testRLtrRtl() {
-        expectBidi(REQ_R, "abc " + ALEF + BET + GIMEL, "0001111", R);
+        expectNativeBidi(REQ_R, "abc " + ALEF + BET + GIMEL, "2221111", R);
     }
     
     //@SmallTest
     public void testLAllRtl() {
-        expectBidi(REQ_L, ALEF + SP + ALEF + BET + GIMEL + DALET, "111111", L);
+        expectNativeBidi(REQ_L, ALEF + SP + ALEF + BET + GIMEL + DALET, "111111", L);
     }
     
     //@SmallTest
     public void testLRtlLtr() {
-        expectBidi(REQ_L,  ALEF + BET + GIMEL + " abc", "1110000", L);
-    }
-    
-    private void expectBidi(int dir, String text, 
-            String expectedLevels, int expectedDir) {
-        char[] chs = text.toCharArray();
-        int n = chs.length;
-        byte[] chInfo = new byte[n];
-        
-        int resultDir = StaticLayout.bidi(dir, chs, chInfo, n, false);
-        
-        {
-            StringBuilder sb = new StringBuilder("info:");
-            for (int i = 0; i < n; ++i) {
-                sb.append(" ").append(String.valueOf(chInfo[i]));
-            }
-            Log.i("BIDI", sb.toString());
-        }
-        
-        char[] resultLevelChars = new char[n];
-        for (int i = 0; i < n; ++i) {
-            resultLevelChars[i] = (char)('0' + chInfo[i]);
-        }
-        String resultLevels = new String(resultLevelChars);
-        assertEquals("direction", expectedDir, resultDir);
-        assertEquals("levels", expectedLevels, resultLevels);
+        expectNativeBidi(REQ_DL,  ALEF + BET + GIMEL + " abc", "1111222", R);
     }
     
     //@SmallTest
     public void testNativeBidi() {
-        // native bidi returns levels, not simply directions
-        expectNativeBidi(REQ_DL,  ALEF + BET + GIMEL + " abc", "1111222", R);
+        expectNativeBidi(REQ_L,  ALEF + BET + GIMEL + " abc", "1110000", L);
     }
     
     private void expectNativeBidi(int dir, String text, 
diff --git a/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java b/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java
new file mode 100644
index 0000000..53f78a5
--- /dev/null
+++ b/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java
@@ -0,0 +1,233 @@
+/*
+ * 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 android.text;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.Layout.Directions;
+import android.text.StaticLayoutTest.LayoutBuilder;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.Formatter;
+
+import junit.framework.TestCase;
+
+public class StaticLayoutDirectionsTest extends TestCase {
+    private static final char ALEF = '\u05d0';
+
+    private static Directions dirs(int ... dirs) {
+        return new Directions(dirs);
+    }
+
+    private static final int LVL1_1 = 1 | (1 << Layout.RUN_LEVEL_SHIFT);
+    private static final int LVL2_1 = 1 | (2 << Layout.RUN_LEVEL_SHIFT);
+    private static final int LVL2_2 = 2 | (2 << Layout.RUN_LEVEL_SHIFT);
+    
+    private static String[] texts = {
+        "",
+        " ",
+        "a",
+        "a1",
+        "aA",
+        "a1b",
+        "a1A",
+        "aA1",
+        "aAb",
+        "aA1B",
+        "aA1B2",
+
+        // rtl
+        "A",
+        "A1",
+        "Aa",
+        "A1B",
+        "A1a",
+        "Aa1",
+        "AaB"
+    };
+
+    // Expected directions are an array of start/length+level pairs,
+    // in visual order from the leading margin.
+    private static Directions[] expected = {
+        Layout.DIRS_ALL_LEFT_TO_RIGHT,
+        Layout.DIRS_ALL_LEFT_TO_RIGHT,
+        Layout.DIRS_ALL_LEFT_TO_RIGHT,
+        Layout.DIRS_ALL_LEFT_TO_RIGHT,
+        dirs(0, 1, 1, LVL1_1),
+        Layout.DIRS_ALL_LEFT_TO_RIGHT,
+        dirs(0, 2, 2, LVL1_1),
+        dirs(0, 1, 2, LVL2_1, 1, LVL1_1),
+        dirs(0, 1, 1, LVL1_1, 2, 1),
+        dirs(0, 1, 3, LVL1_1, 2, LVL2_1, 1, LVL1_1),
+        dirs(0, 1, 4, LVL2_1, 3, LVL1_1, 2, LVL2_1, 1, LVL1_1),
+
+        // rtl
+        Layout.DIRS_ALL_RIGHT_TO_LEFT,
+        dirs(0, LVL1_1, 1, LVL2_1),
+        dirs(0, LVL1_1, 1, LVL2_1),
+        dirs(0, LVL1_1, 1, LVL2_1, 2, LVL1_1),
+        dirs(0, LVL1_1, 1, LVL2_2),
+        dirs(0, LVL1_1, 1, LVL2_2),
+        dirs(0, LVL1_1, 1, LVL2_1, 2, LVL1_1),
+    };
+
+    private static String pseudoBidiToReal(String src) {
+        char[] chars = src.toCharArray();
+        for (int j = 0; j < chars.length; ++j) {
+            char c = chars[j];
+            if (c >= 'A' && c <= 'D') {
+                chars[j] = (char)(ALEF + c - 'A');
+            }
+        }
+
+        return new String(chars, 0, chars.length);
+    }
+
+    // @SmallTest
+    public void testDirections() {
+        StringBuilder buf = new StringBuilder("\n");
+        Formatter f = new Formatter(buf);
+
+        LayoutBuilder b = StaticLayoutTest.builder();
+        for (int i = 0; i < texts.length; ++i) {
+            b.setText(pseudoBidiToReal(texts[i]));
+            checkDirections(b.build(), i, b.text, expected, f);
+        }
+        if (buf.length() > 1) {
+            fail(buf.toString());
+        }
+    }
+    
+    // @SmallTest
+    public void testTrailingWhitespace() {
+        LayoutBuilder b = StaticLayoutTest.builder();
+        b.setText(pseudoBidiToReal("Ab   c"));
+        float width = b.paint.measureText(b.text, 0, 5);  // exclude 'c'
+        b.setWidth(Math.round(width));
+        Layout l = b.build();
+        if (l.getLineCount() != 2) {
+            throw new RuntimeException("expected 2 lines, got: " + l.getLineCount());
+        }
+        Directions result = l.getLineDirections(0);
+        Directions expected = dirs(0, LVL1_1, 1, LVL2_1, 2, 3 | (1 << Layout.RUN_LEVEL_SHIFT));
+        expectDirections("split line", expected, result);
+    }
+
+    public void testNextToRightOf() {
+        LayoutBuilder b = StaticLayoutTest.builder();
+        b.setText(pseudoBidiToReal("aA1B2"));
+        // visual a2B1A positions 04321
+        // 0: |a2B1A, strong is sol, after -> 0
+        // 1: a|2B1A, strong is a, after ->, 1
+        // 2: a2|B1A, strong is B, after -> 4
+        // 3: a2B|1A, strong is B, before -> 3
+        // 4: a2B1|A, strong is A, after -> 2
+        // 5: a2B1A|, strong is eol, before -> 5
+        int[] expected = { 0, 1, 4, 3, 2, 5 };
+        Layout l = b.build();
+        int n = 0;
+        for (int i = 1; i < expected.length; ++i) {
+            int t = l.getOffsetToRightOf(n);
+            if (t != expected[i]) {
+                fail("offset[" + i + "] to right of: " + n + " expected: " + 
+                        expected[i] + " got: " + t);
+            }
+            n = t;
+        }
+    }
+
+    public void testNextToLeftOf() {
+        LayoutBuilder b = StaticLayoutTest.builder();
+        b.setText(pseudoBidiToReal("aA1B2"));
+        int[] expected = { 0, 1, 4, 3, 2, 5 };
+        Layout l = b.build();
+        int n = 5;
+        for (int i = expected.length - 1; --i >= 0;) {
+            int t = l.getOffsetToLeftOf(n);
+            if (t != expected[i]) {
+                fail("offset[" + i + "] to left of: " + n + " expected: " + 
+                        expected[i] + " got: " + t);
+            }
+            n = t;
+        }
+    }
+    
+    // utility, not really a test
+    public void testMeasureText1() {
+        LayoutBuilder b = StaticLayoutTest.builder();
+        String text = "ABC"; // "abAB"
+        b.setText(pseudoBidiToReal(text));
+        Layout l = b.build();
+        Directions directions = l.getLineDirections(0);
+        
+        TextPaint workPaint = new TextPaint();
+
+        int dir = -1; // LEFT_TO_RIGHT
+        boolean trailing = true;
+        boolean alt = true;
+        do {
+            dir = -dir;
+            do {
+                trailing = !trailing;
+                for (int offset = 0, end = b.text.length(); offset <= end; ++offset) {
+                    float width = Layout.measureText(b.paint,
+                            workPaint,
+                            b.text,
+                            0, offset, end,
+                            dir, directions,
+                            trailing, false,
+                            null);
+                    Log.i("BIDI", "dir: " + dir + " trail: " + trailing +
+                            " offset: " + offset + " width: " + width);
+                }
+            } while (!trailing);
+        } while (dir > 0);
+        
+    }
+
+    // utility for displaying arrays in hex
+    private static String hexArray(int[] array) {
+        StringBuilder sb = new StringBuilder();
+        sb.append('{');
+        for (int i : array) {
+            if (sb.length() > 1) {
+                sb.append(", ");
+            }
+            sb.append(Integer.toHexString(i));
+        }
+        sb.append('}');
+        return sb.toString();
+    }
+    
+    private void checkDirections(Layout l, int i, String text, 
+            Directions[] expectedDirs, Formatter f) {
+        Directions expected = expectedDirs[i];
+        Directions result = l.getLineDirections(0);
+        if (!Arrays.equals(expected.mDirections, result.mDirections)) {
+            f.format("%n[%2d] '%s', %s != %s", i, text, 
+                    hexArray(expected.mDirections),
+                    hexArray(result.mDirections));
+        }
+    }
+    
+    private void expectDirections(String msg, Directions expected, Directions result) {
+        if (!Arrays.equals(expected.mDirections, result.mDirections)) {
+            fail("expected: " + hexArray(expected.mDirections) + 
+                    " got: " + hexArray(result.mDirections));
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTest.java b/core/tests/coretests/src/android/text/StaticLayoutTest.java
index 1f58a2c..d554a50 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutTest.java
@@ -228,11 +228,11 @@
         }
     }
 
-    private static LayoutBuilder builder() {
+    /* package */ static LayoutBuilder builder() {
         return new LayoutBuilder();
     }
 
-    private static class LayoutBuilder {
+    /* package */ static class LayoutBuilder {
         String text = "This is a test";
         TextPaint paint = new TextPaint(); // default
         int width = 100;
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 17c0778..d32a0b5 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -76,10 +76,30 @@
         subData1D(0, mType.getElementCount(), d);
     }
 
+    public void subData(int off, FieldPacker fp) {
+        int eSize = mType.mElement.getSizeBytes();
+        final byte[] data = fp.getData();
+
+        int count = data.length / eSize;
+        if ((eSize * count) != data.length) {
+            throw new IllegalArgumentException("Field packer length " + data.length +
+                                               " not divisible by element size " + eSize + ".");
+        }
+        data1DChecks(off, count, data.length, data.length);
+        mRS.nAllocationSubData1D(mID, off, count, data, data.length);
+    }
+
     private void data1DChecks(int off, int count, int len, int dataSize) {
         mRS.validate();
-        if((off < 0) || (count < 1) || ((off + count) > mType.getElementCount())) {
-            throw new IllegalArgumentException("Offset or Count out of bounds.");
+        if(off < 0) {
+            throw new IllegalArgumentException("Offset must be >= 0.");
+        }
+        if(count < 1) {
+            throw new IllegalArgumentException("Count must be >= 1.");
+        }
+        if((off + count) > mType.getElementCount()) {
+            throw new IllegalArgumentException("Overflow, Available count " + mType.getElementCount() +
+                                               ", got " + count + " at offset " + off + ".");
         }
         if((len) < dataSize) {
             throw new IllegalArgumentException("Array too small for allocation type.");
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Byte2.java
similarity index 89%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Byte2.java
index 567d57fa..95cf88c 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Byte2.java
@@ -24,12 +24,12 @@
  * @hide
  *
  **/
-public class Vector2f {
-    public Vector2f() {
+public class Byte2 {
+    public Byte2() {
     }
 
-    public float x;
-    public float y;
+    public byte x;
+    public byte y;
 }
 
 
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Byte3.java
similarity index 87%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Byte3.java
index 567d57fa..a6c0ca9 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Byte3.java
@@ -24,12 +24,13 @@
  * @hide
  *
  **/
-public class Vector2f {
-    public Vector2f() {
+public class Byte3 {
+    public Byte3() {
     }
 
-    public float x;
-    public float y;
+    public byte x;
+    public byte y;
+    public byte z;
 }
 
 
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Byte4.java
similarity index 85%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Byte4.java
index 567d57fa..a5bfc61 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Byte4.java
@@ -24,14 +24,15 @@
  * @hide
  *
  **/
-public class Vector2f {
-    public Vector2f() {
+public class Byte4 {
+    public Byte4() {
     }
 
-    public float x;
-    public float y;
+    public byte x;
+    public byte y;
+    public byte z;
+    public byte w;
 }
 
 
 
-
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index 10ef05a..7b155fe 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -126,6 +126,77 @@
         return rs.mElement_USER_F32;
     }
 
+    public static Element USER_ELEMENT(RenderScript rs) {
+        if(rs.mElement_USER_ELEMENT == null) {
+            rs.mElement_USER_ELEMENT = createUser(rs, DataType.RS_ELEMENT);
+        }
+        return rs.mElement_USER_ELEMENT;
+    }
+
+    public static Element USER_TYPE(RenderScript rs) {
+        if(rs.mElement_USER_TYPE == null) {
+            rs.mElement_USER_TYPE = createUser(rs, DataType.RS_TYPE);
+        }
+        return rs.mElement_USER_TYPE;
+    }
+
+    public static Element USER_ALLOCATION(RenderScript rs) {
+        if(rs.mElement_USER_ALLOCATION == null) {
+            rs.mElement_USER_ALLOCATION = createUser(rs, DataType.RS_ALLOCATION);
+        }
+        return rs.mElement_USER_ALLOCATION;
+    }
+
+    public static Element USER_SAMPLER(RenderScript rs) {
+        if(rs.mElement_USER_SAMPLER == null) {
+            rs.mElement_USER_SAMPLER = createUser(rs, DataType.RS_SAMPLER);
+        }
+        return rs.mElement_USER_SAMPLER;
+    }
+
+    public static Element USER_SCRIPT(RenderScript rs) {
+        if(rs.mElement_USER_SCRIPT == null) {
+            rs.mElement_USER_SCRIPT = createUser(rs, DataType.RS_SCRIPT);
+        }
+        return rs.mElement_USER_SCRIPT;
+    }
+
+    public static Element USER_MESH(RenderScript rs) {
+        if(rs.mElement_USER_MESH == null) {
+            rs.mElement_USER_MESH = createUser(rs, DataType.RS_MESH);
+        }
+        return rs.mElement_USER_MESH;
+    }
+
+    public static Element USER_PROGRAM_FRAGMENT(RenderScript rs) {
+        if(rs.mElement_USER_PROGRAM_FRAGMENT == null) {
+            rs.mElement_USER_PROGRAM_FRAGMENT = createUser(rs, DataType.RS_PROGRAM_FRAGMENT);
+        }
+        return rs.mElement_USER_PROGRAM_FRAGMENT;
+    }
+
+    public static Element USER_PROGRAM_VERTEX(RenderScript rs) {
+        if(rs.mElement_USER_PROGRAM_VERTEX == null) {
+            rs.mElement_USER_PROGRAM_VERTEX = createUser(rs, DataType.RS_PROGRAM_VERTEX);
+        }
+        return rs.mElement_USER_PROGRAM_VERTEX;
+    }
+
+    public static Element USER_PROGRAM_RASTER(RenderScript rs) {
+        if(rs.mElement_USER_PROGRAM_RASTER == null) {
+            rs.mElement_USER_PROGRAM_RASTER = createUser(rs, DataType.RS_PROGRAM_RASTER);
+        }
+        return rs.mElement_USER_PROGRAM_RASTER;
+    }
+
+    public static Element USER_PROGRAM_STORE(RenderScript rs) {
+        if(rs.mElement_USER_PROGRAM_STORE == null) {
+            rs.mElement_USER_PROGRAM_STORE = createUser(rs, DataType.RS_PROGRAM_STORE);
+        }
+        return rs.mElement_USER_PROGRAM_STORE;
+    }
+
+
     public static Element A_8(RenderScript rs) {
         if(rs.mElement_A_8 == null) {
             rs.mElement_A_8 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_A);
diff --git a/graphics/java/android/renderscript/FieldPacker.java b/graphics/java/android/renderscript/FieldPacker.java
index b26e47d..6d55c7e 100644
--- a/graphics/java/android/renderscript/FieldPacker.java
+++ b/graphics/java/android/renderscript/FieldPacker.java
@@ -33,21 +33,24 @@
         }
     }
 
-    void reset() {
+    public void reset() {
         mPos = 0;
     }
+    public void reset(int i) {
+        mPos = i;
+    }
 
-    void addI8(byte v) {
+    public void addI8(byte v) {
         mData[mPos++] = v;
     }
 
-    void addI16(short v) {
+    public void addI16(short v) {
         align(2);
         mData[mPos++] = (byte)(v & 0xff);
         mData[mPos++] = (byte)(v >> 8);
     }
 
-    void addI32(int v) {
+    public void addI32(int v) {
         align(4);
         mData[mPos++] = (byte)(v & 0xff);
         mData[mPos++] = (byte)((v >> 8) & 0xff);
@@ -55,7 +58,7 @@
         mData[mPos++] = (byte)((v >> 24) & 0xff);
     }
 
-    void addI64(long v) {
+    public void addI64(long v) {
         align(8);
         mData[mPos++] = (byte)(v & 0xff);
         mData[mPos++] = (byte)((v >> 8) & 0xff);
@@ -67,14 +70,14 @@
         mData[mPos++] = (byte)((v >> 56) & 0xff);
     }
 
-    void addU8(short v) {
+    public void addU8(short v) {
         if ((v < 0) || (v > 0xff)) {
             throw new IllegalArgumentException("Saving value out of range for type");
         }
         mData[mPos++] = (byte)v;
     }
 
-    void addU16(int v) {
+    public void addU16(int v) {
         if ((v < 0) || (v > 0xffff)) {
             throw new IllegalArgumentException("Saving value out of range for type");
         }
@@ -83,7 +86,7 @@
         mData[mPos++] = (byte)(v >> 8);
     }
 
-    void addU32(long v) {
+    public void addU32(long v) {
         if ((v < 0) || (v > 0xffffffff)) {
             throw new IllegalArgumentException("Saving value out of range for type");
         }
@@ -94,7 +97,7 @@
         mData[mPos++] = (byte)((v >> 24) & 0xff);
     }
 
-    void addU64(long v) {
+    public void addU64(long v) {
         if (v < 0) {
             throw new IllegalArgumentException("Saving value out of range for type");
         }
@@ -109,15 +112,135 @@
         mData[mPos++] = (byte)((v >> 56) & 0xff);
     }
 
-    void addF32(float v) {
+    public void addF32(float v) {
         addI32(Float.floatToRawIntBits(v));
     }
 
-    void addF64(float v) {
+    public void addF64(float v) {
         addI64(Double.doubleToRawLongBits(v));
     }
 
-    final byte[] getData() {
+    public void addObj(BaseObj obj) {
+        if (obj != null) {
+            addI32(obj.getID());
+        } else {
+            addI32(0);
+        }
+    }
+
+    public void addF32(Float2 v) {
+        addF32(v.x);
+        addF32(v.y);
+    }
+    public void addF32(Float3 v) {
+        addF32(v.x);
+        addF32(v.y);
+        addF32(v.z);
+    }
+    public void addF32(Float4 v) {
+        addF32(v.x);
+        addF32(v.y);
+        addF32(v.z);
+        addF32(v.w);
+    }
+
+    public void addI8(Byte2 v) {
+        addI8(v.x);
+        addI8(v.y);
+    }
+    public void addI8(Byte3 v) {
+        addI8(v.x);
+        addI8(v.y);
+        addI8(v.z);
+    }
+    public void addI8(Byte4 v) {
+        addI8(v.x);
+        addI8(v.y);
+        addI8(v.z);
+        addI8(v.w);
+    }
+
+    public void addU8(Short2 v) {
+        addU8(v.x);
+        addU8(v.y);
+    }
+    public void addU8(Short3 v) {
+        addU8(v.x);
+        addU8(v.y);
+        addU8(v.z);
+    }
+    public void addU8(Short4 v) {
+        addU8(v.x);
+        addU8(v.y);
+        addU8(v.z);
+        addU8(v.w);
+    }
+
+    public void addI16(Short2 v) {
+        addI16(v.x);
+        addI16(v.y);
+    }
+    public void addI16(Short3 v) {
+        addI16(v.x);
+        addI16(v.y);
+        addI16(v.z);
+    }
+    public void addI16(Short4 v) {
+        addI16(v.x);
+        addI16(v.y);
+        addI16(v.z);
+        addI16(v.w);
+    }
+
+    public void addU16(Int2 v) {
+        addU16(v.x);
+        addU16(v.y);
+    }
+    public void addU16(Int3 v) {
+        addU16(v.x);
+        addU16(v.y);
+        addU16(v.z);
+    }
+    public void addU16(Int4 v) {
+        addU16(v.x);
+        addU16(v.y);
+        addU16(v.z);
+        addU16(v.w);
+    }
+
+    public void addI32(Int2 v) {
+        addI32(v.x);
+        addI32(v.y);
+    }
+    public void addI32(Int3 v) {
+        addI32(v.x);
+        addI32(v.y);
+        addI32(v.z);
+    }
+    public void addI32(Int4 v) {
+        addI32(v.x);
+        addI32(v.y);
+        addI32(v.z);
+        addI32(v.w);
+    }
+
+    public void addU32(Int2 v) {
+        addU32(v.x);
+        addU32(v.y);
+    }
+    public void addU32(Int3 v) {
+        addU32(v.x);
+        addU32(v.y);
+        addU32(v.z);
+    }
+    public void addU32(Int4 v) {
+        addU32(v.x);
+        addU32(v.y);
+        addU32(v.z);
+        addU32(v.w);
+    }
+
+    public final byte[] getData() {
         return mData;
     }
 
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Float2.java
similarity index 93%
rename from graphics/java/android/renderscript/Vector2f.java
rename to graphics/java/android/renderscript/Float2.java
index 567d57fa..8fea91f 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Float2.java
@@ -24,8 +24,8 @@
  * @hide
  *
  **/
-public class Vector2f {
-    public Vector2f() {
+public class Float2 {
+    public Float2() {
     }
 
     public float x;
diff --git a/graphics/java/android/renderscript/Vector3f.java b/graphics/java/android/renderscript/Float3.java
similarity index 94%
rename from graphics/java/android/renderscript/Vector3f.java
rename to graphics/java/android/renderscript/Float3.java
index f2842f3..9d9e406 100644
--- a/graphics/java/android/renderscript/Vector3f.java
+++ b/graphics/java/android/renderscript/Float3.java
@@ -24,8 +24,8 @@
  * @hide
  *
  **/
-public class Vector3f {
-    public Vector3f() {
+public class Float3 {
+    public Float3() {
     }
 
     public float x;
diff --git a/graphics/java/android/renderscript/Vector4f.java b/graphics/java/android/renderscript/Float4.java
similarity index 94%
rename from graphics/java/android/renderscript/Vector4f.java
rename to graphics/java/android/renderscript/Float4.java
index fabd959..a703e80 100644
--- a/graphics/java/android/renderscript/Vector4f.java
+++ b/graphics/java/android/renderscript/Float4.java
@@ -24,8 +24,8 @@
  * @hide
  *
  **/
-public class Vector4f {
-    public Vector4f() {
+public class Float4 {
+    public Float4() {
     }
 
     public float x;
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Int2.java
similarity index 89%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Int2.java
index 567d57fa..56e2fe9 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Int2.java
@@ -24,12 +24,12 @@
  * @hide
  *
  **/
-public class Vector2f {
-    public Vector2f() {
+public class Int2 {
+    public Int2() {
     }
 
-    public float x;
-    public float y;
+    public int x;
+    public int y;
 }
 
 
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Int3.java
similarity index 88%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Int3.java
index 567d57fa..1b27509 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Int3.java
@@ -24,12 +24,13 @@
  * @hide
  *
  **/
-public class Vector2f {
-    public Vector2f() {
+public class Int3 {
+    public Int3() {
     }
 
-    public float x;
-    public float y;
+    public int x;
+    public int y;
+    public int z;
 }
 
 
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Int4.java
similarity index 86%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Int4.java
index 567d57fa..3d6f3f5 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Int4.java
@@ -24,14 +24,15 @@
  * @hide
  *
  **/
-public class Vector2f {
-    public Vector2f() {
+public class Int4 {
+    public Int4() {
     }
 
-    public float x;
-    public float y;
+    public int x;
+    public int y;
+    public int z;
+    public int w;
 }
 
 
 
-
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Long2.java
similarity index 89%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Long2.java
index 567d57fa..11ead2f 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Long2.java
@@ -24,12 +24,12 @@
  * @hide
  *
  **/
-public class Vector2f {
-    public Vector2f() {
+public class Long2 {
+    public Long2() {
     }
 
-    public float x;
-    public float y;
+    public long x;
+    public long y;
 }
 
 
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Long3.java
similarity index 87%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Long3.java
index 567d57fa..1604532 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Long3.java
@@ -24,12 +24,13 @@
  * @hide
  *
  **/
-public class Vector2f {
-    public Vector2f() {
+public class Long3 {
+    public Long3() {
     }
 
-    public float x;
-    public float y;
+    public long x;
+    public long y;
+    public long z;
 }
 
 
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Long4.java
similarity index 85%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Long4.java
index 567d57fa..2fd2747 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Long4.java
@@ -24,14 +24,15 @@
  * @hide
  *
  **/
-public class Vector2f {
-    public Vector2f() {
+public class Long4 {
+    public Long4() {
     }
 
-    public float x;
-    public float y;
+    public long x;
+    public long y;
+    public long z;
+    public long w;
 }
 
 
 
-
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index a935243..db2a3fd 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -203,6 +203,17 @@
     Element mElement_USER_I32;
     Element mElement_USER_F32;
 
+    Element mElement_USER_ELEMENT;
+    Element mElement_USER_TYPE;
+    Element mElement_USER_ALLOCATION;
+    Element mElement_USER_SAMPLER;
+    Element mElement_USER_SCRIPT;
+    Element mElement_USER_MESH;
+    Element mElement_USER_PROGRAM_FRAGMENT;
+    Element mElement_USER_PROGRAM_VERTEX;
+    Element mElement_USER_PROGRAM_RASTER;
+    Element mElement_USER_PROGRAM_STORE;
+
     Element mElement_A_8;
     Element mElement_RGB_565;
     Element mElement_RGB_888;
diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java
index 57ccfa3..0d21368 100644
--- a/graphics/java/android/renderscript/Script.java
+++ b/graphics/java/android/renderscript/Script.java
@@ -42,6 +42,10 @@
         }
     }
 
+    protected void invoke(int slot) {
+        mRS.nScriptInvoke(mID, slot);
+    }
+
     Script(int id, RenderScript rs) {
         super(rs);
         mID = id;
@@ -145,5 +149,48 @@
 
     }
 
+
+    public static class FieldBase {
+        protected Element mElement;
+        protected Type mType;
+        protected Allocation mAllocation;
+
+        protected void init(RenderScript rs, int dimx) {
+            mAllocation = Allocation.createSized(rs, mElement, dimx);
+            mType = mAllocation.getType();
+        }
+
+        protected FieldBase() {
+        }
+
+        public Element getElement() {
+            return mElement;
+        }
+
+        public Type getType() {
+            return mType;
+        }
+
+        public Allocation getAllocation() {
+            return mAllocation;
+        }
+
+        //@Override
+        public void updateAllocation() {
+        }
+
+
+        //
+        /*
+        public class ScriptField_UserField
+            extends android.renderscript.Script.FieldBase {
+
+            protected
+
+        }
+
+        */
+
+    }
 }
 
diff --git a/graphics/java/android/renderscript/ScriptC.java b/graphics/java/android/renderscript/ScriptC.java
index bb99e23..f5d5b2f 100644
--- a/graphics/java/android/renderscript/ScriptC.java
+++ b/graphics/java/android/renderscript/ScriptC.java
@@ -37,6 +37,47 @@
         super(id, rs);
     }
 
+    protected ScriptC(RenderScript rs, Resources resources, int resourceID, boolean isRoot) {
+        super(0, rs);
+        mID = internalCreate(rs, resources, resourceID, isRoot);
+    }
+
+
+    private static synchronized int internalCreate(RenderScript rs, Resources resources, int resourceID, boolean isRoot) {
+        byte[] pgm;
+        int pgmLength;
+        InputStream is = resources.openRawResource(resourceID);
+        try {
+            try {
+                pgm = new byte[1024];
+                pgmLength = 0;
+                while(true) {
+                    int bytesLeft = pgm.length - pgmLength;
+                    if (bytesLeft == 0) {
+                        byte[] buf2 = new byte[pgm.length * 2];
+                        System.arraycopy(pgm, 0, buf2, 0, pgm.length);
+                        pgm = buf2;
+                        bytesLeft = pgm.length - pgmLength;
+                    }
+                    int bytesRead = is.read(pgm, pgmLength, bytesLeft);
+                    if (bytesRead <= 0) {
+                        break;
+                    }
+                    pgmLength += bytesRead;
+                }
+            } finally {
+                is.close();
+            }
+        } catch(IOException e) {
+            throw new Resources.NotFoundException();
+        }
+
+        rs.nScriptCBegin();
+        rs.nScriptCSetScript(pgm, 0, pgmLength);
+        rs.nScriptSetRoot(isRoot);
+        return rs.nScriptCCreate();
+    }
+
     public static class Builder extends Script.Builder {
         byte[] mProgram;
         int mProgramLength;
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Short2.java
similarity index 89%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Short2.java
index 567d57fa..426801f 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Short2.java
@@ -24,12 +24,12 @@
  * @hide
  *
  **/
-public class Vector2f {
-    public Vector2f() {
+public class Short2 {
+    public Short2() {
     }
 
-    public float x;
-    public float y;
+    public short x;
+    public short y;
 }
 
 
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Short3.java
similarity index 87%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Short3.java
index 567d57fa..7b9c305 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Short3.java
@@ -24,12 +24,13 @@
  * @hide
  *
  **/
-public class Vector2f {
-    public Vector2f() {
+public class Short3 {
+    public Short3() {
     }
 
-    public float x;
-    public float y;
+    public short x;
+    public short y;
+    public short z;
 }
 
 
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Short4.java
similarity index 85%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Short4.java
index 567d57fa..9a474e2 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Short4.java
@@ -24,14 +24,15 @@
  * @hide
  *
  **/
-public class Vector2f {
-    public Vector2f() {
+public class Short4 {
+    public Short4() {
     }
 
-    public float x;
-    public float y;
+    public short x;
+    public short y;
+    public short z;
+    public short w;
 }
 
 
 
-
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
index 98464a0..0b06022 100644
--- a/libs/rs/Android.mk
+++ b/libs/rs/Android.mk
@@ -76,16 +76,18 @@
 LOCAL_SRC_FILES:= \
 	rsAdapter.cpp \
 	rsAllocation.cpp \
+	rsAnimation.cpp \
 	rsComponent.cpp \
 	rsContext.cpp \
 	rsDevice.cpp \
 	rsElement.cpp \
-        rsFileA3D.cpp \
+    rsFileA3D.cpp \
 	rsLight.cpp \
 	rsLocklessFifo.cpp \
 	rsObjectBase.cpp \
 	rsMatrix.cpp \
-        rsMesh.cpp \
+    rsMesh.cpp \
+    rsMutex.cpp \
 	rsNoise.cpp \
 	rsProgram.cpp \
 	rsProgramFragment.cpp \
@@ -96,7 +98,8 @@
 	rsScript.cpp \
 	rsScriptC.cpp \
 	rsScriptC_Lib.cpp \
-        rsShaderCache.cpp \
+    rsShaderCache.cpp \
+	rsSignal.cpp \
 	rsSimpleMesh.cpp \
 	rsThreadIO.cpp \
 	rsType.cpp \
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index d280f50..7415ba9 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -30,6 +30,7 @@
 typedef void * RsAdapter1D;
 typedef void * RsAdapter2D;
 typedef void * RsAllocation;
+typedef void * RsAnimation;
 typedef void * RsContext;
 typedef void * RsDevice;
 typedef void * RsElement;
@@ -205,7 +206,27 @@
 enum RsError {
     RS_ERROR_NONE,
     RS_ERROR_BAD_SHADER,
-    RS_ERROR_BAD_SCRIPT
+    RS_ERROR_BAD_SCRIPT,
+    RS_ERROR_BAD_VALUE,
+    RS_ERROR_OUT_OF_MEMORY
+};
+
+enum RsAnimationInterpolation {
+    RS_ANIMATION_INTERPOLATION_STEP,
+    RS_ANIMATION_INTERPOLATION_LINEAR,
+    RS_ANIMATION_INTERPOLATION_BEZIER,
+    RS_ANIMATION_INTERPOLATION_CARDINAL,
+    RS_ANIMATION_INTERPOLATION_HERMITE,
+    RS_ANIMATION_INTERPOLATION_BSPLINE
+};
+
+enum RsAnimationEdge {
+    RS_ANIMATION_EDGE_UNDEFINED,
+    RS_ANIMATION_EDGE_CONSTANT,
+    RS_ANIMATION_EDGE_GRADIENT,
+    RS_ANIMATION_EDGE_CYCLE,
+    RS_ANIMATION_EDGE_OSCILLATE,
+    RS_ANIMATION_EDGE_CYLE_RELATIVE
 };
 
 #ifndef NO_RS_FUNCS
diff --git a/libs/rs/java/Fountain/res/raw/fountain2.rs b/libs/rs/java/Fountain/res/raw/fountain2.rs
index 3301140..5d36e35 100644
--- a/libs/rs/java/Fountain/res/raw/fountain2.rs
+++ b/libs/rs/java/Fountain/res/raw/fountain2.rs
@@ -1,9 +1,9 @@
 // Fountain test script
 #pragma version(1)
 
-#include "rs_types.rsh"
-#include "rs_math.rsh"
-#include "rs_graphics.rsh"
+#include "../../../../scriptc/rs_types.rsh"
+#include "../../../../scriptc/rs_math.rsh"
+#include "../../../../scriptc/rs_graphics.rsh"
 
 static int newPart = 0;
 
@@ -12,15 +12,15 @@
     int rate;
     int count;
     float r, g, b;
-    rs_allocation partBuffer;
     rs_mesh partMesh;
+    rs_allocation partBuffer;
 } Control_t;
 Control_t *Control;
 
 typedef struct Point_s{
     float2 delta;
-    float2 position;
-    unsigned int color;
+    rs_position2 pos;
+    rs_color4u color;
 } Point_t;
 Point_t *point;
 
@@ -33,8 +33,6 @@
 
     if (rate) {
         float rMax = ((float)rate) * 0.005f;
-        int x = Control->x;
-        int y = Control->y;
         int color = ((int)(Control->r * 255.f)) |
                     ((int)(Control->g * 255.f)) << 8 |
                     ((int)(Control->b * 255.f)) << 16 |
@@ -42,9 +40,11 @@
         Point_t * np = &p[newPart];
 
         while (rate--) {
-            np->delta = vec2Rand(rMax);
-            np->position.x = x;
-            np->position.y = y;
+            np->delta.x = rand(rMax);
+            np->delta.y = rand(rMax);
+            //np->delta = vec2Rand(rMax);
+            np->pos.x = Control->x;
+            np->pos.y = Control->y;
             np->color = color;
             newPart++;
             np++;
@@ -57,13 +57,13 @@
 
     for (ct=0; ct < count; ct++) {
         float dy = p->delta.y + 0.15f;
-        float posy = p->position.y + dy;
+        float posy = p->pos.y + dy;
         if ((posy > height) && (dy > 0)) {
             dy *= -0.3f;
         }
         p->delta.y = dy;
-        p->position.x += p->delta.x;
-        p->position.y = posy;
+        p->pos.x += p->delta.x;
+        p->pos.y = posy;
         p++;
     }
 
diff --git a/libs/rs/java/ImageProcessing/res/raw/threshold2.rs b/libs/rs/java/ImageProcessing/res/raw/threshold2.rs
new file mode 100644
index 0000000..9f687b5
--- /dev/null
+++ b/libs/rs/java/ImageProcessing/res/raw/threshold2.rs
@@ -0,0 +1,49 @@
+#pragma version(1)
+
+#include "../../../../scriptc/rs_types.rsh"
+#include "../../../../scriptc/rs_math.rsh"
+#include "../../../../scriptc/rs_graphics.rsh"
+
+typedef struct Params_s{
+    int inHeight;
+    int inWidth;
+    int outHeight;
+    int outWidth;
+    float threshold;
+} Params_t;
+
+Params_t * Params;
+rs_color4u * InPixel;
+rs_color4u * OutPixel;
+
+
+int main() {
+    int t = uptimeMillis();
+
+    rs_color4u *in = InPixel;
+    rs_color4u *out = OutPixel;
+
+    int count = Params->inWidth * Params->inHeight;
+    int i;
+    float threshold = Params->threshold * 255.f;
+
+    for (i = 0; i < count; i++) {
+        float luminance = 0.2125f * in->x +
+                          0.7154f * in->y +
+                          0.0721f * in->z;
+        if (luminance > threshold) {
+            *out = *in;
+        } else {
+            *((int *)out) = *((int *)in) & 0xff000000;
+        }
+
+        in++;
+        out++;
+    }
+
+    t= uptimeMillis() - t;
+    debugI32("Filter time", t);
+
+    sendToClient(&count, 1, 4, 0);
+    return 0;
+}
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index cb9937c..08aa369 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -480,3 +480,13 @@
 	param uint32_t slot
 	}
 
+AnimationCreate {
+	param const float *inValues
+	param const float *outValues
+	param uint32_t valueCount
+	param RsAnimationInterpolation interp
+	param RsAnimationEdge pre
+	param RsAnimationEdge post
+	ret RsAnimation
+	}
+
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index 4e8278d..e5ff1d7 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -170,6 +170,7 @@
         glGenerateMipmap(GL_TEXTURE_2D);
     }
 
+    rsc->checkError("Allocation::uploadToTexture");
 }
 
 void Allocation::deferedUploadToBufferObject(const Context *rsc)
@@ -201,6 +202,7 @@
     glBindBuffer(GL_ARRAY_BUFFER, mBufferID);
     glBufferData(GL_ARRAY_BUFFER, mType->getSizeBytes(), getPtr(), GL_DYNAMIC_DRAW);
     glBindBuffer(GL_ARRAY_BUFFER, 0);
+    rsc->checkError("Allocation::uploadToBufferObject");
 }
 
 void Allocation::uploadCheck(const Context *rsc)
diff --git a/libs/rs/rsAnimation.cpp b/libs/rs/rsAnimation.cpp
new file mode 100644
index 0000000..48c9334
--- /dev/null
+++ b/libs/rs/rsAnimation.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#include "rsContext.h"
+#include "rsAnimation.h"
+
+
+using namespace android;
+using namespace android::renderscript;
+
+/*
+Animation::Animation(Context *rsc) : ObjectBase(rsc)
+{
+    mAllocFile = __FILE__;
+    mAllocLine = __LINE__;
+
+    mValuesInput = NULL;
+    mValuesOutput = NULL;
+    mValueCount = 0;
+    mInterpolation = RS_ANIMATION_INTERPOLATION_STEP;
+    mEdgePre = RS_ANIMATION_EDGE_UNDEFINED;
+    mEdgePost = RS_ANIMATION_EDGE_UNDEFINED;
+    mInputMin = 0;
+    mInputMax = 0;
+}
+
+Animation * Animation::create(Context *rsc,
+                              const float *inValues, const float *outValues,
+                              uint32_t valueCount, RsAnimationInterpolation interp,
+                              RsAnimationEdge pre, RsAnimationEdge post)
+{
+    if (valueCount < 2) {
+        rsc->setError(RS_ERROR_BAD_VALUE, "Animations require more than 2 values.");
+        return NULL;
+    }
+    Animation *a = new Animation(rsc);
+    if (!a) {
+        rsc->setError(RS_ERROR_OUT_OF_MEMORY);
+        return NULL;
+    }
+
+    float *vin = (float *)malloc(valueCount * sizeof(float));
+    float *vout = (float *)malloc(valueCount * sizeof(float));
+    a->mValuesInput = vin;
+    a->mValuesOutput = vout;
+    if (a->mValuesInput == NULL || a->mValuesOutput == NULL) {
+        delete a;
+        rsc->setError(RS_ERROR_OUT_OF_MEMORY);
+        return NULL;
+    }
+
+    a->mEdgePre = pre;
+    a->mEdgePost = post;
+    a->mInterpolation = interp;
+    a->mValueCount = valueCount;
+
+    memcpy(vin, inValues, valueCount * sizeof(float));
+    memcpy(vout, outValues, valueCount * sizeof(float));
+    a->mInputMin = inValues[0];
+    a->mInputMax = inValues[0];
+
+    bool needSort = false;
+    for (uint32_t ct=1; ct < valueCount; ct++) {
+        if (a->mInputMin > vin[ct]) {
+            needSort = true;
+            a->mInputMin = vin[ct];
+        }
+        if (a->mInputMax < vin[ct]) {
+            a->mInputMax = vin[ct];
+        } else {
+            needSort = true;
+        }
+    }
+
+    while (1) {
+        bool changed = false;
+        for (uint32_t ct=1; ct < valueCount; ct++) {
+            if (vin[ct-1] > vin[ct]) {
+                float t = vin[ct-1];
+                vin[ct-1] = vin[ct];
+                vin[ct] = t;
+                t = vout[ct-1];
+                vout[ct-1] = vout[ct];
+                vout[ct] = t;
+                changed = true;
+            }
+        }
+        if (!changed) break;
+    }
+
+    return a;
+}
+*/
+
+
+/////////////////////////////////////////
+//
+
+namespace android {
+namespace renderscript {
+
+RsAnimation rsi_AnimationCreate(Context *rsc,
+                                const float *inValues,
+                                const float *outValues,
+                                uint32_t valueCount,
+                                RsAnimationInterpolation interp,
+                                RsAnimationEdge pre,
+                                RsAnimationEdge post)
+{
+    //LOGE("rsi_ElementCreate %i %i %i %i", dt, dk, norm, vecSize);
+    Animation *a = NULL;//Animation::create(rsc, inValues, outValues, valueCount, interp, pre, post);
+    if (a != NULL) {
+        a->incUserRef();
+    }
+    return (RsAnimation)a;
+}
+
+
+}
+}
+
diff --git a/libs/rs/rsAnimation.h b/libs/rs/rsAnimation.h
new file mode 100644
index 0000000..b8db661
--- /dev/null
+++ b/libs/rs/rsAnimation.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#ifndef ANDROID_RS_ANIMATION_H
+#define ANDROID_RS_ANIMATION_H
+
+#include "rsUtils.h"
+#include "rsObjectBase.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+class Animation : public ObjectBase
+{
+public:
+    ~Animation();
+
+    static Animation * create(Context *rsc,
+                              const float *inValues, const float *outValues,
+                              uint32_t valueCount, RsAnimationInterpolation,
+                              RsAnimationEdge pre, RsAnimationEdge post);
+
+    float eval(float) const;
+
+
+protected:
+    Animation(Context *rsc);
+
+
+
+    float evalInRange(float) const;
+
+
+
+    const float *mValuesInput;
+    const float *mValuesOutput;
+    uint32_t mValueCount;
+    RsAnimationInterpolation mInterpolation;
+    RsAnimationEdge mEdgePre;
+    RsAnimationEdge mEdgePost;
+
+    // derived
+    float mInputMin;
+    float mInputMax;
+};
+
+
+
+
+}
+}
+#endif //ANDROID_STRUCTURED_ELEMENT_H
+
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index d8a9a99..4107229 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -664,8 +664,7 @@
 
 bool Context::objDestroyOOBInit()
 {
-    int status = pthread_mutex_init(&mObjDestroy.mMutex, NULL);
-    if (status) {
+    if (!mObjDestroy.mMutex.init()) {
         LOGE("Context::ObjDestroyOOBInit mutex init failure");
         return false;
     }
@@ -675,9 +674,8 @@
 void Context::objDestroyOOBRun()
 {
     if (mObjDestroy.mNeedToEmpty) {
-        int status = pthread_mutex_lock(&mObjDestroy.mMutex);
-        if (status) {
-            LOGE("Context::ObjDestroyOOBRun: error %i locking for OOBRun.", status);
+        if (!mObjDestroy.mMutex.lock()) {
+            LOGE("Context::ObjDestroyOOBRun: error locking for OOBRun.");
             return;
         }
 
@@ -686,35 +684,25 @@
         }
         mObjDestroy.mDestroyList.clear();
         mObjDestroy.mNeedToEmpty = false;
-
-        status = pthread_mutex_unlock(&mObjDestroy.mMutex);
-        if (status) {
-            LOGE("Context::ObjDestroyOOBRun: error %i unlocking for set condition.", status);
-        }
+        mObjDestroy.mMutex.unlock();
     }
 }
 
 void Context::objDestroyOOBDestroy()
 {
     rsAssert(!mObjDestroy.mNeedToEmpty);
-    pthread_mutex_destroy(&mObjDestroy.mMutex);
 }
 
 void Context::objDestroyAdd(ObjectBase *obj)
 {
-    int status = pthread_mutex_lock(&mObjDestroy.mMutex);
-    if (status) {
-        LOGE("Context::ObjDestroyOOBRun: error %i locking for OOBRun.", status);
+    if (!mObjDestroy.mMutex.lock()) {
+        LOGE("Context::ObjDestroyOOBRun: error locking for OOBRun.");
         return;
     }
 
     mObjDestroy.mNeedToEmpty = true;
     mObjDestroy.mDestroyList.add(obj);
-
-    status = pthread_mutex_unlock(&mObjDestroy.mMutex);
-    if (status) {
-        LOGE("Context::ObjDestroyOOBRun: error %i unlocking for set condition.", status);
-    }
+    mObjDestroy.mMutex.unlock();
 }
 
 uint32_t Context::getMessageToClient(void *data, size_t *receiveLen, size_t bufferLen, bool wait)
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 82c3687..8e755a9 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -18,6 +18,7 @@
 #define ANDROID_RS_CONTEXT_H
 
 #include "rsUtils.h"
+#include "rsMutex.h"
 
 #include "rsThreadIO.h"
 #include "rsType.h"
@@ -161,7 +162,7 @@
     void dumpDebug() const;
     void checkError(const char *) const;
     const char * getError(RsError *);
-    void setError(RsError e, const char *msg);
+    void setError(RsError e, const char *msg = NULL);
 
     mutable const ObjectBase * mObjHead;
 
@@ -227,7 +228,7 @@
 
 
     struct ObjDestroyOOB {
-        pthread_mutex_t mMutex;
+        Mutex mMutex;
         Vector<ObjectBase *> mDestroyList;
         bool mNeedToEmpty;
     };
diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp
index c796520..76ca32e 100644
--- a/libs/rs/rsLocklessFifo.cpp
+++ b/libs/rs/rsLocklessFifo.cpp
@@ -17,7 +17,7 @@
 #include "rsLocklessFifo.h"
 
 using namespace android;
-
+using namespace android::renderscript;
 
 LocklessCommandFifo::LocklessCommandFifo()
 {
@@ -128,15 +128,19 @@
     //dumpState("flush 2");
 }
 
+void LocklessCommandFifo::wait()
+{
+    while(isEmpty() && !mInShutdown) {
+        mSignalToControl.set();
+        mSignalToWorker.wait();
+    }
+}
+
 const void * LocklessCommandFifo::get(uint32_t *command, uint32_t *bytesData)
 {
     while(1) {
         //dumpState("get");
-        while(isEmpty() && !mInShutdown) {
-            mSignalToControl.set();
-            mSignalToWorker.wait();
-        }
-
+        wait();
         if (mInShutdown) {
             *command = 0;
             *bytesData = 0;
@@ -192,79 +196,3 @@
     LOGV("%s  put %p, get %p,  buf %p,  end %p", s, mPut, mGet, mBuffer, mEnd);
 }
 
-LocklessCommandFifo::Signal::Signal()
-{
-    mSet = true;
-}
-
-LocklessCommandFifo::Signal::~Signal()
-{
-    pthread_mutex_destroy(&mMutex);
-    pthread_cond_destroy(&mCondition);
-}
-
-bool LocklessCommandFifo::Signal::init()
-{
-    int status = pthread_mutex_init(&mMutex, NULL);
-    if (status) {
-        LOGE("LocklessFifo mutex init failure");
-        return false;
-    }
-
-    status = pthread_cond_init(&mCondition, NULL);
-    if (status) {
-        LOGE("LocklessFifo condition init failure");
-        pthread_mutex_destroy(&mMutex);
-        return false;
-    }
-
-    return true;
-}
-
-void LocklessCommandFifo::Signal::set()
-{
-    int status;
-
-    status = pthread_mutex_lock(&mMutex);
-    if (status) {
-        LOGE("LocklessCommandFifo: error %i locking for set condition.", status);
-        return;
-    }
-
-    mSet = true;
-
-    status = pthread_cond_signal(&mCondition);
-    if (status) {
-        LOGE("LocklessCommandFifo: error %i on set condition.", status);
-    }
-
-    status = pthread_mutex_unlock(&mMutex);
-    if (status) {
-        LOGE("LocklessCommandFifo: error %i unlocking for set condition.", status);
-    }
-}
-
-void LocklessCommandFifo::Signal::wait()
-{
-    int status;
-
-    status = pthread_mutex_lock(&mMutex);
-    if (status) {
-        LOGE("LocklessCommandFifo: error %i locking for condition.", status);
-        return;
-    }
-
-    if (!mSet) {
-        status = pthread_cond_wait(&mCondition, &mMutex);
-        if (status) {
-            LOGE("LocklessCommandFifo: error %i waiting on condition.", status);
-        }
-    }
-    mSet = false;
-
-    status = pthread_mutex_unlock(&mMutex);
-    if (status) {
-        LOGE("LocklessCommandFifo: error %i unlocking for condition.", status);
-    }
-}
-
diff --git a/libs/rs/rsLocklessFifo.h b/libs/rs/rsLocklessFifo.h
index d0a4356..ae906ca 100644
--- a/libs/rs/rsLocklessFifo.h
+++ b/libs/rs/rsLocklessFifo.h
@@ -19,8 +19,10 @@
 
 
 #include "rsUtils.h"
+#include "rsSignal.h"
 
 namespace android {
+namespace renderscript {
 
 
 // A simple FIFO to be used as a producer / consumer between two
@@ -37,24 +39,7 @@
     LocklessCommandFifo();
     ~LocklessCommandFifo();
 
-
 protected:
-    class Signal {
-    public:
-        Signal();
-        ~Signal();
-
-        bool init();
-
-        void set();
-        void wait();
-
-    protected:
-        bool mSet;
-        pthread_mutex_t mMutex;
-        pthread_cond_t mCondition;
-    };
-
     uint8_t * volatile mPut;
     uint8_t * volatile mGet;
     uint8_t * mBuffer;
@@ -65,14 +50,14 @@
     Signal mSignalToWorker;
     Signal mSignalToControl;
 
-
-
 public:
     void * reserve(uint32_t bytes);
     void commit(uint32_t command, uint32_t bytes);
     void commitSync(uint32_t command, uint32_t bytes);
 
     void flush();
+    void wait();
+
     const void * get(uint32_t *command, uint32_t *bytesData);
     void next();
 
@@ -88,4 +73,5 @@
 
 
 }
+}
 #endif
diff --git a/libs/rs/rsMutex.cpp b/libs/rs/rsMutex.cpp
new file mode 100644
index 0000000..37752f2
--- /dev/null
+++ b/libs/rs/rsMutex.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#include "rsMutex.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Mutex::Mutex()
+{
+}
+
+Mutex::~Mutex()
+{
+    pthread_mutex_destroy(&mMutex);
+}
+
+bool Mutex::init()
+{
+    int status = pthread_mutex_init(&mMutex, NULL);
+    if (status) {
+        LOGE("Mutex::Mutex init failure");
+        return false;
+    }
+    return true;
+}
+
+bool Mutex::lock()
+{
+    int status;
+    status = pthread_mutex_lock(&mMutex);
+    if (status) {
+        LOGE("Mutex: error %i locking.", status);
+        return false;
+    }
+    return true;
+}
+
+bool Mutex::unlock()
+{
+    int status;
+    status = pthread_mutex_unlock(&mMutex);
+    if (status) {
+        LOGE("Mutex error %i unlocking.", status);
+        return false;
+    }
+    return true;
+}
+
+
diff --git a/graphics/java/android/renderscript/Vector2f.java b/libs/rs/rsMutex.h
similarity index 69%
copy from graphics/java/android/renderscript/Vector2f.java
copy to libs/rs/rsMutex.h
index 567d57fa..47725d7 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/libs/rs/rsMutex.h
@@ -14,24 +14,30 @@
  * limitations under the License.
  */
 
-package android.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
+#ifndef ANDROID_RS_MUTEX_H
+#define ANDROID_RS_MUTEX_H
 
 
-/**
- * @hide
- *
- **/
-public class Vector2f {
-    public Vector2f() {
-    }
+#include "rsUtils.h"
 
-    public float x;
-    public float y;
+namespace android {
+namespace renderscript {
+
+class Mutex {
+public:
+    Mutex();
+    ~Mutex();
+
+    bool init();
+    bool lock();
+    bool unlock();
+
+protected:
+    pthread_mutex_t mMutex;
+};
+
+}
 }
 
-
-
+#endif
 
diff --git a/libs/rs/rsSignal.cpp b/libs/rs/rsSignal.cpp
new file mode 100644
index 0000000..9239bfd
--- /dev/null
+++ b/libs/rs/rsSignal.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#include "rsSignal.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Signal::Signal()
+{
+    mSet = true;
+}
+
+Signal::~Signal()
+{
+    pthread_mutex_destroy(&mMutex);
+    pthread_cond_destroy(&mCondition);
+}
+
+bool Signal::init()
+{
+    int status = pthread_mutex_init(&mMutex, NULL);
+    if (status) {
+        LOGE("LocklessFifo mutex init failure");
+        return false;
+    }
+
+    status = pthread_cond_init(&mCondition, NULL);
+    if (status) {
+        LOGE("LocklessFifo condition init failure");
+        pthread_mutex_destroy(&mMutex);
+        return false;
+    }
+
+    return true;
+}
+
+void Signal::set()
+{
+    int status;
+
+    status = pthread_mutex_lock(&mMutex);
+    if (status) {
+        LOGE("LocklessCommandFifo: error %i locking for set condition.", status);
+        return;
+    }
+
+    mSet = true;
+
+    status = pthread_cond_signal(&mCondition);
+    if (status) {
+        LOGE("LocklessCommandFifo: error %i on set condition.", status);
+    }
+
+    status = pthread_mutex_unlock(&mMutex);
+    if (status) {
+        LOGE("LocklessCommandFifo: error %i unlocking for set condition.", status);
+    }
+}
+
+void Signal::wait()
+{
+    int status;
+
+    status = pthread_mutex_lock(&mMutex);
+    if (status) {
+        LOGE("LocklessCommandFifo: error %i locking for condition.", status);
+        return;
+    }
+
+    if (!mSet) {
+        status = pthread_cond_wait(&mCondition, &mMutex);
+        if (status) {
+            LOGE("LocklessCommandFifo: error %i waiting on condition.", status);
+        }
+    }
+    mSet = false;
+
+    status = pthread_mutex_unlock(&mMutex);
+    if (status) {
+        LOGE("LocklessCommandFifo: error %i unlocking for condition.", status);
+    }
+}
+
diff --git a/graphics/java/android/renderscript/Vector2f.java b/libs/rs/rsSignal.h
similarity index 65%
copy from graphics/java/android/renderscript/Vector2f.java
copy to libs/rs/rsSignal.h
index 567d57fa..2e760f1 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/libs/rs/rsSignal.h
@@ -14,24 +14,33 @@
  * limitations under the License.
  */
 
-package android.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
+#ifndef ANDROID_RS_SIGNAL_H
+#define ANDROID_RS_SIGNAL_H
 
 
-/**
- * @hide
- *
- **/
-public class Vector2f {
-    public Vector2f() {
-    }
+#include "rsUtils.h"
 
-    public float x;
-    public float y;
+namespace android {
+namespace renderscript {
+
+class Signal {
+public:
+    Signal();
+    ~Signal();
+
+    bool init();
+
+    void set();
+    void wait();
+
+protected:
+    bool mSet;
+    pthread_mutex_t mMutex;
+    pthread_cond_t mCondition;
+};
+
+}
 }
 
-
-
+#endif
 
diff --git a/libs/rs/rsg_ScriptJavaClass.cpp b/libs/rs/rsg_ScriptJavaClass.cpp
index cee9f52..0169b98 100644
--- a/libs/rs/rsg_ScriptJavaClass.cpp
+++ b/libs/rs/rsg_ScriptJavaClass.cpp
@@ -7,8 +7,12 @@
 struct Element;
 
 struct ElementField {
+    // An Element Field is a combination of an Element with a name assigned.
+
     const char *name;
     Element *e;
+
+
     ElementField(const char *n, Element *_e) {
         name = n;
         e = _e;
@@ -20,12 +24,21 @@
 };
 
 struct Element {
+    // An Element can take one of two forms.
+    // 1: Basic.  It contains a single basic type and vector size.
+    // 2: Complex.  It contains a list of fields with names.  Each field
+    // will in turn be another element.
+
     ElementField *fields;
-    size_t fieldCount;
+    size_t fieldCount;  // If field count is 0, the element is a Basic type.
     const char *name;
     bool generated;
 
+    // The basic data type from RenderScript.h
     RsDataType compType;
+
+    // The vector size of the data type for float2, float3, ....
+    // Allowed sizes are 2,3,4,8,16
     uint32_t compVectorSize;
 
     Element() {
diff --git a/libs/rs/scriptc/rs_geom.rsh b/libs/rs/scriptc/rs_geom.rsh
new file mode 100644
index 0000000..6e9e9fc
--- /dev/null
+++ b/libs/rs/scriptc/rs_geom.rsh
@@ -0,0 +1,26 @@
+
+extern float3 __attribute__((overloadable)) cross(float3, float3);
+extern float4 __attribute__((overloadable)) cross(float4, float4);
+
+//extern float __attribute__((overloadable)) dot(float, float);
+extern float __attribute__((overloadable)) dot(float2, float2);
+extern float __attribute__((overloadable)) dot(float3, float3);
+extern float __attribute__((overloadable)) dot(float4, float4);
+
+//extern float __attribute__((overloadable)) distance(float, float);
+extern float __attribute__((overloadable)) distance(float2, float2);
+extern float __attribute__((overloadable)) distance(float3, float3);
+extern float __attribute__((overloadable)) distance(float4, float4);
+
+//extern float __attribute__((overloadable)) length(float);
+extern float __attribute__((overloadable)) length(float2);
+extern float __attribute__((overloadable)) length(float3);
+extern float __attribute__((overloadable)) length(float4);
+
+extern float2 __attribute__((overloadable)) normalize(float2);
+extern float3 __attribute__((overloadable)) normalize(float3);
+extern float4 __attribute__((overloadable)) normalize(float4);
+
+
+
+
diff --git a/libs/rs/scriptc/rs_graphics.rsh b/libs/rs/scriptc/rs_graphics.rsh
index 70cd562..0f03732 100644
--- a/libs/rs/scriptc/rs_graphics.rsh
+++ b/libs/rs/scriptc/rs_graphics.rsh
@@ -1,5 +1,7 @@
 
 
+extern float rand(float max);
+
 extern float2 vec2Rand(float len);
 
 extern float3 float3Norm(float3);
diff --git a/libs/rs/scriptc/rs_math.rsh b/libs/rs/scriptc/rs_math.rsh
index 613c7ca..fba0f8f 100644
--- a/libs/rs/scriptc/rs_math.rsh
+++ b/libs/rs/scriptc/rs_math.rsh
@@ -1,264 +1,262 @@
 // Float ops
 
 extern float __attribute__((overloadable)) abs(float);
-extern float2 __attribute__((overloadable)) abs(float2);
-extern float3 __attribute__((overloadable)) abs(float3);
-extern float4 __attribute__((overloadable)) abs(float4);
-extern float8 __attribute__((overloadable)) abs(float8);
-extern float16 __attribute__((overloadable)) abs(float16);
+//extern float2 __attribute__((overloadable)) abs(float2);
+//extern float3 __attribute__((overloadable)) abs(float3);
+//extern float4 __attribute__((overloadable)) abs(float4);
+//extern float8 __attribute__((overloadable)) abs(float8);
+//extern float16 __attribute__((overloadable)) abs(float16);
 
 extern float __attribute__((overloadable)) acos(float);
-extern float2 __attribute__((overloadable)) acos(float2);
-extern float3 __attribute__((overloadable)) acos(float3);
-extern float4 __attribute__((overloadable)) acos(float4);
-extern float8 __attribute__((overloadable)) acos(float8);
-extern float16 __attribute__((overloadable)) acos(float16);
+//extern float2 __attribute__((overloadable)) acos(float2);
+//extern float3 __attribute__((overloadable)) acos(float3);
+//extern float4 __attribute__((overloadable)) acos(float4);
+//extern float8 __attribute__((overloadable)) acos(float8);
+//extern float16 __attribute__((overloadable)) acos(float16);
 
 extern float __attribute__((overloadable)) asin(float);
-extern float2 __attribute__((overloadable)) asin(float2);
-extern float3 __attribute__((overloadable)) asin(float3);
-extern float4 __attribute__((overloadable)) asin(float4);
-extern float8 __attribute__((overloadable)) asin(float8);
-extern float16 __attribute__((overloadable)) asin(float16);
+//extern float2 __attribute__((overloadable)) asin(float2);
+//extern float3 __attribute__((overloadable)) asin(float3);
+//extern float4 __attribute__((overloadable)) asin(float4);
+//extern float8 __attribute__((overloadable)) asin(float8);
+//extern float16 __attribute__((overloadable)) asin(float16);
 
 extern float __attribute__((overloadable)) atan(float);
-extern float2 __attribute__((overloadable)) atan(float2);
-extern float3 __attribute__((overloadable)) atan(float3);
-extern float4 __attribute__((overloadable)) atan(float4);
-extern float8 __attribute__((overloadable)) atan(float8);
-extern float16 __attribute__((overloadable)) atan(float16);
+//extern float2 __attribute__((overloadable)) atan(float2);
+//extern float3 __attribute__((overloadable)) atan(float3);
+//extern float4 __attribute__((overloadable)) atan(float4);
+//extern float8 __attribute__((overloadable)) atan(float8);
+//extern float16 __attribute__((overloadable)) atan(float16);
 
 extern float __attribute__((overloadable)) atan2(float, float);
-extern float2 __attribute__((overloadable)) atan2(float2, float2);
-extern float3 __attribute__((overloadable)) atan2(float3, float3);
-extern float4 __attribute__((overloadable)) atan2(float4, float4);
-extern float8 __attribute__((overloadable)) atan2(float8, float8);
-extern float16 __attribute__((overloadable)) atan2(float16, float16);
+//extern float2 __attribute__((overloadable)) atan2(float2, float2);
+//extern float3 __attribute__((overloadable)) atan2(float3, float3);
+//extern float4 __attribute__((overloadable)) atan2(float4, float4);
+//extern float8 __attribute__((overloadable)) atan2(float8, float8);
+//extern float16 __attribute__((overloadable)) atan2(float16, float16);
 
 extern float __attribute__((overloadable)) ceil(float);
-extern float2 __attribute__((overloadable)) ceil(float2);
-extern float3 __attribute__((overloadable)) ceil(float3);
-extern float4 __attribute__((overloadable)) ceil(float4);
-extern float8 __attribute__((overloadable)) ceil(float8);
-extern float16 __attribute__((overloadable)) ceil(float16);
+//extern float2 __attribute__((overloadable)) ceil(float2);
+//extern float3 __attribute__((overloadable)) ceil(float3);
+//extern float4 __attribute__((overloadable)) ceil(float4);
+//extern float8 __attribute__((overloadable)) ceil(float8);
+//extern float16 __attribute__((overloadable)) ceil(float16);
 
 extern float __attribute__((overloadable)) clamp(float, float, float);
-extern float2 __attribute__((overloadable)) clamp(float2, float2, float2);
-extern float3 __attribute__((overloadable)) clamp(float3, float3, float3);
-extern float4 __attribute__((overloadable)) clamp(float4, float4, float4);
-extern float8 __attribute__((overloadable)) clamp(float8, float8, float8);
-extern float16 __attribute__((overloadable)) clamp(float16, float16, float16);
-extern float __attribute__((overloadable)) clamp(float, float, float);
-extern float2 __attribute__((overloadable)) clamp(float2, float, float);
-extern float3 __attribute__((overloadable)) clamp(float3, float, float);
-extern float4 __attribute__((overloadable)) clamp(float4, float, float);
-extern float8 __attribute__((overloadable)) clamp(float8, float, float);
-extern float16 __attribute__((overloadable)) clamp(float16, float, float);
+//extern float2 __attribute__((overloadable)) clamp(float2, float2, float2);
+//extern float3 __attribute__((overloadable)) clamp(float3, float3, float3);
+//extern float4 __attribute__((overloadable)) clamp(float4, float4, float4);
+//extern float8 __attribute__((overloadable)) clamp(float8, float8, float8);
+//extern float16 __attribute__((overloadable)) clamp(float16, float16, float16);
+//extern float2 __attribute__((overloadable)) clamp(float2, float, float);
+//extern float3 __attribute__((overloadable)) clamp(float3, float, float);
+//extern float4 __attribute__((overloadable)) clamp(float4, float, float);
+//extern float8 __attribute__((overloadable)) clamp(float8, float, float);
+//extern float16 __attribute__((overloadable)) clamp(float16, float, float);
 
 extern float __attribute__((overloadable)) copysign(float, float);
-extern float2 __attribute__((overloadable)) copysign(float2, float2);
-extern float3 __attribute__((overloadable)) copysign(float3, float3);
-extern float4 __attribute__((overloadable)) copysign(float4, float4);
-extern float8 __attribute__((overloadable)) copysign(float8, float8);
-extern float16 __attribute__((overloadable)) copysign(float16, float16);
+//extern float2 __attribute__((overloadable)) copysign(float2, float2);
+//extern float3 __attribute__((overloadable)) copysign(float3, float3);
+//extern float4 __attribute__((overloadable)) copysign(float4, float4);
+//extern float8 __attribute__((overloadable)) copysign(float8, float8);
+//extern float16 __attribute__((overloadable)) copysign(float16, float16);
 
 extern float __attribute__((overloadable)) cos(float);
-extern float2 __attribute__((overloadable)) cos(float2);
-extern float3 __attribute__((overloadable)) cos(float3);
-extern float4 __attribute__((overloadable)) cos(float4);
-extern float8 __attribute__((overloadable)) cos(float8);
-extern float16 __attribute__((overloadable)) cos(float16);
+//extern float2 __attribute__((overloadable)) cos(float2);
+//extern float3 __attribute__((overloadable)) cos(float3);
+//extern float4 __attribute__((overloadable)) cos(float4);
+//extern float8 __attribute__((overloadable)) cos(float8);
+//extern float16 __attribute__((overloadable)) cos(float16);
 
 extern float __attribute__((overloadable)) degrees(float);
-extern float2 __attribute__((overloadable)) degrees(float2);
-extern float3 __attribute__((overloadable)) degrees(float3);
-extern float4 __attribute__((overloadable)) degrees(float4);
-extern float8 __attribute__((overloadable)) degrees(float8);
-extern float16 __attribute__((overloadable)) degrees(float16);
+//extern float2 __attribute__((overloadable)) degrees(float2);
+//extern float3 __attribute__((overloadable)) degrees(float3);
+//extern float4 __attribute__((overloadable)) degrees(float4);
+//extern float8 __attribute__((overloadable)) degrees(float8);
+//extern float16 __attribute__((overloadable)) degrees(float16);
 
 extern float __attribute__((overloadable)) exp(float);
-extern float2 __attribute__((overloadable)) exp(float2);
-extern float3 __attribute__((overloadable)) exp(float3);
-extern float4 __attribute__((overloadable)) exp(float4);
-extern float8 __attribute__((overloadable)) exp(float8);
-extern float16 __attribute__((overloadable)) exp(float16);
+//extern float2 __attribute__((overloadable)) exp(float2);
+//extern float3 __attribute__((overloadable)) exp(float3);
+//extern float4 __attribute__((overloadable)) exp(float4);
+//extern float8 __attribute__((overloadable)) exp(float8);
+//extern float16 __attribute__((overloadable)) exp(float16);
 
 extern float __attribute__((overloadable)) exp2(float);
-extern float2 __attribute__((overloadable)) exp2(float2);
-extern float3 __attribute__((overloadable)) exp2(float3);
-extern float4 __attribute__((overloadable)) exp2(float4);
-extern float8 __attribute__((overloadable)) exp2(float8);
-extern float16 __attribute__((overloadable)) exp2(float16);
+//extern float2 __attribute__((overloadable)) exp2(float2);
+//extern float3 __attribute__((overloadable)) exp2(float3);
+//extern float4 __attribute__((overloadable)) exp2(float4);
+//extern float8 __attribute__((overloadable)) exp2(float8);
+//extern float16 __attribute__((overloadable)) exp2(float16);
 
 extern float __attribute__((overloadable)) exp10(float);
-extern float2 __attribute__((overloadable)) exp10(float2);
-extern float3 __attribute__((overloadable)) exp10(float3);
-extern float4 __attribute__((overloadable)) exp10(float4);
-extern float8 __attribute__((overloadable)) exp10(float8);
-extern float16 __attribute__((overloadable)) exp10(float16);
+//extern float2 __attribute__((overloadable)) exp10(float2);
+//extern float3 __attribute__((overloadable)) exp10(float3);
+//extern float4 __attribute__((overloadable)) exp10(float4);
+//extern float8 __attribute__((overloadable)) exp10(float8);
+//extern float16 __attribute__((overloadable)) exp10(float16);
 
 extern float __attribute__((overloadable)) fabs(float);
-extern float2 __attribute__((overloadable)) fabs(float2);
-extern float3 __attribute__((overloadable)) fabs(float3);
-extern float4 __attribute__((overloadable)) fabs(float4);
-extern float8 __attribute__((overloadable)) fabs(float8);
-extern float16 __attribute__((overloadable)) fabs(float16);
+//extern float2 __attribute__((overloadable)) fabs(float2);
+//extern float3 __attribute__((overloadable)) fabs(float3);
+//extern float4 __attribute__((overloadable)) fabs(float4);
+//extern float8 __attribute__((overloadable)) fabs(float8);
+//extern float16 __attribute__((overloadable)) fabs(float16);
 
 extern float __attribute__((overloadable)) floor(float);
-extern float2 __attribute__((overloadable)) floor(float2);
-extern float3 __attribute__((overloadable)) floor(float3);
-extern float4 __attribute__((overloadable)) floor(float4);
-extern float8 __attribute__((overloadable)) floor(float8);
-extern float16 __attribute__((overloadable)) floor(float16);
+//extern float2 __attribute__((overloadable)) floor(float2);
+//extern float3 __attribute__((overloadable)) floor(float3);
+//extern float4 __attribute__((overloadable)) floor(float4);
+//extern float8 __attribute__((overloadable)) floor(float8);
+//extern float16 __attribute__((overloadable)) floor(float16);
 
 extern float __attribute__((overloadable)) fmax(float, float);
-extern float2 __attribute__((overloadable)) fmax(float2, float2);
-extern float3 __attribute__((overloadable)) fmax(float3, float3);
-extern float4 __attribute__((overloadable)) fmax(float4, float4);
-extern float8 __attribute__((overloadable)) fmax(float8, float8);
-extern float16 __attribute__((overloadable)) fmax(float16, float16);
-extern float2 __attribute__((overloadable)) fmax(float2, float);
-extern float3 __attribute__((overloadable)) fmax(float3, float);
-extern float4 __attribute__((overloadable)) fmax(float4, float);
-extern float8 __attribute__((overloadable)) fmax(float8, float);
-extern float16 __attribute__((overloadable)) fmax(float16, float);
+//extern float2 __attribute__((overloadable)) fmax(float2, float2);
+//extern float3 __attribute__((overloadable)) fmax(float3, float3);
+//extern float4 __attribute__((overloadable)) fmax(float4, float4);
+//extern float8 __attribute__((overloadable)) fmax(float8, float8);
+//extern float16 __attribute__((overloadable)) fmax(float16, float16);
+//extern float2 __attribute__((overloadable)) fmax(float2, float);
+//extern float3 __attribute__((overloadable)) fmax(float3, float);
+//extern float4 __attribute__((overloadable)) fmax(float4, float);
+//extern float8 __attribute__((overloadable)) fmax(float8, float);
+//extern float16 __attribute__((overloadable)) fmax(float16, float);
 
 extern float __attribute__((overloadable)) fmin(float, float);
-extern float2 __attribute__((overloadable)) fmin(float2, float2);
-extern float3 __attribute__((overloadable)) fmin(float3, float3);
-extern float4 __attribute__((overloadable)) fmin(float4, float4);
-extern float8 __attribute__((overloadable)) fmin(float8, float8);
-extern float16 __attribute__((overloadable)) fmin(float16, float16);
-extern float2 __attribute__((overloadable)) fmin(float2, float);
-extern float3 __attribute__((overloadable)) fmin(float3, float);
-extern float4 __attribute__((overloadable)) fmin(float4, float);
-extern float8 __attribute__((overloadable)) fmin(float8, float);
-extern float16 __attribute__((overloadable)) fmin(float16, float);
+//extern float2 __attribute__((overloadable)) fmin(float2, float2);
+//extern float3 __attribute__((overloadable)) fmin(float3, float3);
+//extern float4 __attribute__((overloadable)) fmin(float4, float4);
+//extern float8 __attribute__((overloadable)) fmin(float8, float8);
+//extern float16 __attribute__((overloadable)) fmin(float16, float16);
+//extern float2 __attribute__((overloadable)) fmin(float2, float);
+//extern float3 __attribute__((overloadable)) fmin(float3, float);
+//extern float4 __attribute__((overloadable)) fmin(float4, float);
+//extern float8 __attribute__((overloadable)) fmin(float8, float);
+//extern float16 __attribute__((overloadable)) fmin(float16, float);
 
 extern float __attribute__((overloadable)) fmod(float, float);
-extern float2 __attribute__((overloadable)) fmod(float2, float2);
-extern float3 __attribute__((overloadable)) fmod(float3, float3);
-extern float4 __attribute__((overloadable)) fmod(float4, float4);
-extern float8 __attribute__((overloadable)) fmod(float8, float8);
-extern float16 __attribute__((overloadable)) fmod(float16, float16);
+//extern float2 __attribute__((overloadable)) fmod(float2, float2);
+//extern float3 __attribute__((overloadable)) fmod(float3, float3);
+//extern float4 __attribute__((overloadable)) fmod(float4, float4);
+//extern float8 __attribute__((overloadable)) fmod(float8, float8);
+//extern float16 __attribute__((overloadable)) fmod(float16, float16);
 
 extern float __attribute__((overloadable)) log(float);
-extern float2 __attribute__((overloadable)) log(float2);
-extern float3 __attribute__((overloadable)) log(float3);
-extern float4 __attribute__((overloadable)) log(float4);
-extern float8 __attribute__((overloadable)) log(float8);
-extern float16 __attribute__((overloadable)) log(float16);
+//extern float2 __attribute__((overloadable)) log(float2);
+//extern float3 __attribute__((overloadable)) log(float3);
+//extern float4 __attribute__((overloadable)) log(float4);
+//extern float8 __attribute__((overloadable)) log(float8);
+//extern float16 __attribute__((overloadable)) log(float16);
 
 extern float __attribute__((overloadable)) log2(float);
-extern float2 __attribute__((overloadable)) log2(float2);
-extern float3 __attribute__((overloadable)) log2(float3);
-extern float4 __attribute__((overloadable)) log2(float4);
-extern float8 __attribute__((overloadable)) log2(float8);
-extern float16 __attribute__((overloadable)) log2(float16);
+//extern float2 __attribute__((overloadable)) log2(float2);
+//extern float3 __attribute__((overloadable)) log2(float3);
+//extern float4 __attribute__((overloadable)) log2(float4);
+//extern float8 __attribute__((overloadable)) log2(float8);
+//extern float16 __attribute__((overloadable)) log2(float16);
 
 extern float __attribute__((overloadable)) log10(float);
-extern float2 __attribute__((overloadable)) log10(float2);
-extern float3 __attribute__((overloadable)) log10(float3);
-extern float4 __attribute__((overloadable)) log10(float4);
-extern float8 __attribute__((overloadable)) log10(float8);
-extern float16 __attribute__((overloadable)) log10(float16);
+//extern float2 __attribute__((overloadable)) log10(float2);
+//extern float3 __attribute__((overloadable)) log10(float3);
+//extern float4 __attribute__((overloadable)) log10(float4);
+//extern float8 __attribute__((overloadable)) log10(float8);
+//extern float16 __attribute__((overloadable)) log10(float16);
 
 extern float __attribute__((overloadable)) max(float, float);
-extern float2 __attribute__((overloadable)) max(float2, float2);
-extern float3 __attribute__((overloadable)) max(float3, float3);
-extern float4 __attribute__((overloadable)) max(float4, float4);
-extern float8 __attribute__((overloadable)) max(float8, float8);
-extern float16 __attribute__((overloadable)) max(float16, float16);
+//extern float2 __attribute__((overloadable)) max(float2, float2);
+//extern float3 __attribute__((overloadable)) max(float3, float3);
+//extern float4 __attribute__((overloadable)) max(float4, float4);
+//extern float8 __attribute__((overloadable)) max(float8, float8);
+//extern float16 __attribute__((overloadable)) max(float16, float16);
 
 extern float __attribute__((overloadable)) min(float, float);
-extern float2 __attribute__((overloadable)) min(float2, float2);
-extern float3 __attribute__((overloadable)) min(float3, float3);
-extern float4 __attribute__((overloadable)) min(float4, float4);
-extern float8 __attribute__((overloadable)) min(float8, float8);
-extern float16 __attribute__((overloadable)) min(float16, float16);
+//extern float2 __attribute__((overloadable)) min(float2, float2);
+//extern float3 __attribute__((overloadable)) min(float3, float3);
+//extern float4 __attribute__((overloadable)) min(float4, float4);
+//extern float8 __attribute__((overloadable)) min(float8, float8);
+//extern float16 __attribute__((overloadable)) min(float16, float16);
 
 extern float __attribute__((overloadable)) mix(float, float, float);
-extern float2 __attribute__((overloadable)) mix(float2, float2, float2);
-extern float3 __attribute__((overloadable)) mix(float3, float3, float3);
-extern float4 __attribute__((overloadable)) mix(float4, float4, float4);
-extern float8 __attribute__((overloadable)) mix(float8, float8, float8);
-extern float16 __attribute__((overloadable)) mix(float16, float16, float16);
-extern float __attribute__((overloadable)) mix(float, float, float);
-extern float2 __attribute__((overloadable)) mix(float2, float2, float);
-extern float3 __attribute__((overloadable)) mix(float3, float3, float);
-extern float4 __attribute__((overloadable)) mix(float4, float4, float);
-extern float8 __attribute__((overloadable)) mix(float8, float8, float);
-extern float16 __attribute__((overloadable)) mix(float16, float16, float);
+//extern float2 __attribute__((overloadable)) mix(float2, float2, float2);
+//extern float3 __attribute__((overloadable)) mix(float3, float3, float3);
+//extern float4 __attribute__((overloadable)) mix(float4, float4, float4);
+//extern float8 __attribute__((overloadable)) mix(float8, float8, float8);
+//extern float16 __attribute__((overloadable)) mix(float16, float16, float16);
+//extern float2 __attribute__((overloadable)) mix(float2, float2, float);
+//extern float3 __attribute__((overloadable)) mix(float3, float3, float);
+//extern float4 __attribute__((overloadable)) mix(float4, float4, float);
+//extern float8 __attribute__((overloadable)) mix(float8, float8, float);
+//extern float16 __attribute__((overloadable)) mix(float16, float16, float);
 
 extern float __attribute__((overloadable)) pow(float, float);
-extern float2 __attribute__((overloadable)) pow(float2, float2);
-extern float3 __attribute__((overloadable)) pow(float3, float3);
-extern float4 __attribute__((overloadable)) pow(float4, float4);
-extern float8 __attribute__((overloadable)) pow(float8, float8);
-extern float16 __attribute__((overloadable)) pow(float16, float16);
+//extern float2 __attribute__((overloadable)) pow(float2, float2);
+//extern float3 __attribute__((overloadable)) pow(float3, float3);
+//extern float4 __attribute__((overloadable)) pow(float4, float4);
+//extern float8 __attribute__((overloadable)) pow(float8, float8);
+//extern float16 __attribute__((overloadable)) pow(float16, float16);
 
 extern float __attribute__((overloadable)) radians(float);
-extern float2 __attribute__((overloadable)) radians(float2);
-extern float3 __attribute__((overloadable)) radians(float3);
-extern float4 __attribute__((overloadable)) radians(float4);
-extern float8 __attribute__((overloadable)) radians(float8);
-extern float16 __attribute__((overloadable)) radians(float16);
+//extern float2 __attribute__((overloadable)) radians(float2);
+//extern float3 __attribute__((overloadable)) radians(float3);
+//extern float4 __attribute__((overloadable)) radians(float4);
+//extern float8 __attribute__((overloadable)) radians(float8);
+//extern float16 __attribute__((overloadable)) radians(float16);
 
 extern float __attribute__((overloadable)) rint(float);
-extern float2 __attribute__((overloadable)) rint(float2);
-extern float3 __attribute__((overloadable)) rint(float3);
-extern float4 __attribute__((overloadable)) rint(float4);
-extern float8 __attribute__((overloadable)) rint(float8);
-extern float16 __attribute__((overloadable)) rint(float16);
+//extern float2 __attribute__((overloadable)) rint(float2);
+//extern float3 __attribute__((overloadable)) rint(float3);
+//extern float4 __attribute__((overloadable)) rint(float4);
+//extern float8 __attribute__((overloadable)) rint(float8);
+//extern float16 __attribute__((overloadable)) rint(float16);
 
 extern float __attribute__((overloadable)) round(float);
-extern float2 __attribute__((overloadable)) round(float2);
-extern float3 __attribute__((overloadable)) round(float3);
-extern float4 __attribute__((overloadable)) round(float4);
-extern float8 __attribute__((overloadable)) round(float8);
-extern float16 __attribute__((overloadable)) round(float16);
+//extern float2 __attribute__((overloadable)) round(float2);
+//extern float3 __attribute__((overloadable)) round(float3);
+//extern float4 __attribute__((overloadable)) round(float4);
+//extern float8 __attribute__((overloadable)) round(float8);
+//extern float16 __attribute__((overloadable)) round(float16);
 
 extern float __attribute__((overloadable)) rsqrt(float);
-extern float2 __attribute__((overloadable)) rsqrt(float2);
-extern float3 __attribute__((overloadable)) rsqrt(float3);
-extern float4 __attribute__((overloadable)) rsqrt(float4);
-extern float8 __attribute__((overloadable)) rsqrt(float8);
-extern float16 __attribute__((overloadable)) rsqrt(float16);
+//extern float2 __attribute__((overloadable)) rsqrt(float2);
+//extern float3 __attribute__((overloadable)) rsqrt(float3);
+//extern float4 __attribute__((overloadable)) rsqrt(float4);
+//extern float8 __attribute__((overloadable)) rsqrt(float8);
+//extern float16 __attribute__((overloadable)) rsqrt(float16);
 
 extern float __attribute__((overloadable)) sign(float);
-extern float2 __attribute__((overloadable)) sign(float2);
-extern float3 __attribute__((overloadable)) sign(float3);
-extern float4 __attribute__((overloadable)) sign(float4);
-extern float8 __attribute__((overloadable)) sign(float8);
-extern float16 __attribute__((overloadable)) sign(float16);
+//extern float2 __attribute__((overloadable)) sign(float2);
+//extern float3 __attribute__((overloadable)) sign(float3);
+//extern float4 __attribute__((overloadable)) sign(float4);
+//extern float8 __attribute__((overloadable)) sign(float8);
+//extern float16 __attribute__((overloadable)) sign(float16);
 
 extern float __attribute__((overloadable)) sin(float);
-extern float2 __attribute__((overloadable)) sin(float2);
-extern float3 __attribute__((overloadable)) sin(float3);
-extern float4 __attribute__((overloadable)) sin(float4);
-extern float8 __attribute__((overloadable)) sin(float8);
-extern float16 __attribute__((overloadable)) sin(float16);
+//extern float2 __attribute__((overloadable)) sin(float2);
+//extern float3 __attribute__((overloadable)) sin(float3);
+//extern float4 __attribute__((overloadable)) sin(float4);
+//extern float8 __attribute__((overloadable)) sin(float8);
+//extern float16 __attribute__((overloadable)) sin(float16);
 
 extern float __attribute__((overloadable)) sqrt(float);
-extern float2 __attribute__((overloadable)) sqrt(float2);
-extern float3 __attribute__((overloadable)) sqrt(float3);
-extern float4 __attribute__((overloadable)) sqrt(float4);
-extern float8 __attribute__((overloadable)) sqrt(float8);
-extern float16 __attribute__((overloadable)) sqrt(float16);
+//extern float2 __attribute__((overloadable)) sqrt(float2);
+//extern float3 __attribute__((overloadable)) sqrt(float3);
+//extern float4 __attribute__((overloadable)) sqrt(float4);
+//extern float8 __attribute__((overloadable)) sqrt(float8);
+//extern float16 __attribute__((overloadable)) sqrt(float16);
 
 extern float __attribute__((overloadable)) tan(float);
-extern float2 __attribute__((overloadable)) tan(float2);
-extern float3 __attribute__((overloadable)) tan(float3);
-extern float4 __attribute__((overloadable)) tan(float4);
-extern float8 __attribute__((overloadable)) tan(float8);
-extern float16 __attribute__((overloadable)) tan(float16);
+//extern float2 __attribute__((overloadable)) tan(float2);
+//extern float3 __attribute__((overloadable)) tan(float3);
+//extern float4 __attribute__((overloadable)) tan(float4);
+//extern float8 __attribute__((overloadable)) tan(float8);
+//extern float16 __attribute__((overloadable)) tan(float16);
 
 extern float __attribute__((overloadable)) trunc(float);
-extern float2 __attribute__((overloadable)) trunc(float2);
-extern float3 __attribute__((overloadable)) trunc(float3);
-extern float4 __attribute__((overloadable)) trunc(float4);
-extern float8 __attribute__((overloadable)) trunc(float8);
-extern float16 __attribute__((overloadable)) trunc(float16);
+//extern float2 __attribute__((overloadable)) trunc(float2);
+//extern float3 __attribute__((overloadable)) trunc(float3);
+//extern float4 __attribute__((overloadable)) trunc(float4);
+//extern float8 __attribute__((overloadable)) trunc(float8);
+//extern float16 __attribute__((overloadable)) trunc(float16);
 
 
 
@@ -268,11 +266,11 @@
 // Int ops
 
 extern int __attribute__((overloadable)) abs(int);
-extern int2 __attribute__((overloadable)) abs(int2);
-extern int3 __attribute__((overloadable)) abs(int3);
-extern int4 __attribute__((overloadable)) abs(int4);
-extern int8 __attribute__((overloadable)) abs(int8);
-extern int16 __attribute__((overloadable)) abs(int16);
+//extern int2 __attribute__((overloadable)) abs(int2);
+//extern int3 __attribute__((overloadable)) abs(int3);
+//extern int4 __attribute__((overloadable)) abs(int4);
+//extern int8 __attribute__((overloadable)) abs(int8);
+//extern int16 __attribute__((overloadable)) abs(int16);
 
 
 
diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh
index 4198a74..b710146 100644
--- a/libs/rs/scriptc/rs_types.rsh
+++ b/libs/rs/scriptc/rs_types.rsh
@@ -68,4 +68,29 @@
 typedef int int16 __attribute__((ext_vector_type(16)));
 
 
+// RS_KIND_POSITION
+typedef float rs_position1;
+typedef float2 rs_position2;
+typedef float3 rs_position3;
+typedef float4 rs_position4;
+
+// RS_KIND_COLOR
+typedef float3 rs_color3f;
+typedef float4 rs_color4f;
+typedef uchar4 rs_color4u;
+
+// RS_KIND_NORMAL
+typedef float3 rs_normal;
+
+// RS_KIND_POINT_SIZE
+typedef float rs_point_size;
+
+// RS_KIND_TEXTURE
+typedef float rs_texture_coord1;
+typedef float2 rs_texture_coord2;
+typedef float3 rs_texture_coord3;
+typedef float4 rs_texture_coord4;
+
+// RS_KIND_INDEX
+typedef ushort rs_index;
 
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 9e4a16b..28bc599 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -117,6 +117,37 @@
      */
     public static final String KEY_LOCATION_CHANGED = "location";
 
+    /**
+     * Broadcast intent action indicating that the GPS has either been
+     * enabled or disabled. An intent extra provides this state as a boolean,
+     * where {@code true} means enabled.
+     * @see #EXTRA_GPS_ENABLED
+     *
+     * {@hide}
+     */
+    public static final String GPS_ENABLED_CHANGE_ACTION =
+        "android.location.GPS_ENABLED_CHANGE";
+
+    /**
+     * Broadcast intent action indicating that the GPS has either started or
+     * stopped receiving GPS fixes. An intent extra provides this state as a
+     * boolean, where {@code true} means that the GPS is actively receiving fixes.
+     * @see #EXTRA_GPS_ENABLED
+     *
+     * {@hide}
+     */
+    public static final String GPS_FIX_CHANGE_ACTION =
+        "android.location.GPS_FIX_CHANGE";
+
+    /**
+     * The lookup key for a boolean that indicates whether GPS is enabled or
+     * disabled. {@code true} means GPS is enabled. Retrieve it with
+     * {@link android.content.Intent#getBooleanExtra(String,boolean)}.
+     *
+     * {@hide}
+     */
+    public static final String EXTRA_GPS_ENABLED = "enabled";
+
     // Map from LocationListeners to their associated ListenerTransport objects
     private HashMap<LocationListener,ListenerTransport> mListeners =
         new HashMap<LocationListener,ListenerTransport>();
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index a5466d1..d3a71b3 100755
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -23,6 +23,7 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
+import android.location.LocationManager;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.util.Log;
@@ -81,7 +82,7 @@
     private final Context mContext;
     
     // parent gps location provider
-    private final GpsLocationProvider mGpsLocationProvider;
+    private final LocationManager mLocationManager;
     
     // configuration of notificaiton behavior
     private boolean mPlaySounds = false;
@@ -93,25 +94,25 @@
         
     public static class GpsNiNotification
     {
-    	int notificationId;
-    	int niType;
-    	boolean needNotify;
-    	boolean needVerify;
-    	boolean privacyOverride;
-    	int timeout;
-    	int defaultResponse;
-    	String requestorId;
-    	String text;
-    	int requestorIdEncoding;
-    	int textEncoding;
-    	Bundle extras;
+        public int notificationId;
+        public int niType;
+        public boolean needNotify;
+        public boolean needVerify;
+        public boolean privacyOverride;
+        public int timeout;
+        public int defaultResponse;
+        public String requestorId;
+        public String text;
+        public int requestorIdEncoding;
+        public int textEncoding;
+        public Bundle extras;
     };
     
     public static class GpsNiResponse {
-    	/* User reponse, one of the values in GpsUserResponseType */
-    	int userResponse;
-    	/* Optional extra data to pass with the user response */
-    	Bundle extras;
+        /* User reponse, one of the values in GpsUserResponseType */
+        int userResponse;
+        /* Optional extra data to pass with the user response */
+        Bundle extras;
     };
     
     /**
@@ -122,63 +123,57 @@
      */
     private Notification mNiNotification;
     
-    public GpsNetInitiatedHandler(Context context, GpsLocationProvider gpsLocationProvider) {
-    	mContext = context;       
-    	mGpsLocationProvider = gpsLocationProvider;
+    public GpsNetInitiatedHandler(Context context) {
+        mContext = context;
+        mLocationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
     }
     
     // Handles NI events from HAL
     public void handleNiNotification(GpsNiNotification notif)
     {
-    	if (DEBUG) Log.d(TAG, "handleNiNotification" + " notificationId: " + notif.notificationId 
-    			+ " requestorId: " + notif.requestorId + " text: " + notif.text);
-    	
-    	// Notify and verify with immediate pop-up
-    	if (notif.needNotify && notif.needVerify && mPopupImmediately)
-    	{
-    		// Popup the dialog box now
-    		openNiDialog(notif);
-    	}
-    	
-    	// Notify only, or delayed pop-up (change mPopupImmediately to FALSE) 
-    	if (notif.needNotify && !notif.needVerify ||
-    		notif.needNotify && notif.needVerify && !mPopupImmediately) 
-    	{
-    		// Show the notification
+        if (DEBUG) Log.d(TAG, "handleNiNotification" + " notificationId: " + notif.notificationId
+                + " requestorId: " + notif.requestorId + " text: " + notif.text);
 
-    		// if mPopupImmediately == FALSE and needVerify == TRUE, a dialog will be opened
-    		// when the user opens the notification message
-    		
-    		setNiNotification(notif);
-    	}
-    	
-    	// ACCEPT cases: 1. Notify, no verify; 2. no notify, no verify; 3. privacy override.
-    	if ( notif.needNotify && !notif.needVerify || 
-    		!notif.needNotify && !notif.needVerify || 
-    		 notif.privacyOverride)
-    	{
-    		try {
-    			mGpsLocationProvider.getNetInitiatedListener().sendNiResponse(notif.notificationId, GPS_NI_RESPONSE_ACCEPT);
-    		} 
-    		catch (RemoteException e)
-    		{
-    			Log.e(TAG, e.getMessage());
-    		}
-    	}
-    	
-    	//////////////////////////////////////////////////////////////////////////
-    	//   A note about timeout
-    	//   According to the protocol, in the need_notify and need_verify case,
-    	//   a default response should be sent when time out.
-    	//   
-    	//   In some GPS hardware, the GPS driver (under HAL) can handle the timeout case
-    	//   and this class GpsNetInitiatedHandler does not need to do anything.
-    	//   
-    	//   However, the UI should at least close the dialog when timeout. Further, 
-    	//   for more general handling, timeout response should be added to the Handler here.
-    	//    	    	
+        // Notify and verify with immediate pop-up
+        if (notif.needNotify && notif.needVerify && mPopupImmediately)
+        {
+            // Popup the dialog box now
+            openNiDialog(notif);
+        }
+
+        // Notify only, or delayed pop-up (change mPopupImmediately to FALSE)
+        if (notif.needNotify && !notif.needVerify ||
+            notif.needNotify && notif.needVerify && !mPopupImmediately)
+        {
+            // Show the notification
+
+            // if mPopupImmediately == FALSE and needVerify == TRUE, a dialog will be opened
+            // when the user opens the notification message
+
+            setNiNotification(notif);
+        }
+
+        // ACCEPT cases: 1. Notify, no verify; 2. no notify, no verify; 3. privacy override.
+        if ( notif.needNotify && !notif.needVerify ||
+            !notif.needNotify && !notif.needVerify ||
+             notif.privacyOverride)
+        {
+            mLocationManager.sendNiResponse(notif.notificationId, GPS_NI_RESPONSE_ACCEPT);
+        }
+
+        //////////////////////////////////////////////////////////////////////////
+        //   A note about timeout
+        //   According to the protocol, in the need_notify and need_verify case,
+        //   a default response should be sent when time out.
+        //
+        //   In some GPS hardware, the GPS driver (under HAL) can handle the timeout case
+        //   and this class GpsNetInitiatedHandler does not need to do anything.
+        //
+        //   However, the UI should at least close the dialog when timeout. Further,
+        //   for more general handling, timeout response should be added to the Handler here.
+        //
     }
-    
+
     // Sets the NI notification.
     private synchronized void setNiNotification(GpsNiNotification notif) {
         NotificationManager notificationManager = (NotificationManager) mContext
@@ -186,272 +181,272 @@
         if (notificationManager == null) {
             return;
         }
-      
-    	String title = getNotifTitle(notif);
-    	String message = getNotifMessage(notif);
-        
+
+        String title = getNotifTitle(notif);
+        String message = getNotifMessage(notif);
+
         if (DEBUG) Log.d(TAG, "setNiNotification, notifyId: " + notif.notificationId +
-        		", title: " + title +
-        		", message: " + message);
-        
-    	// Construct Notification
-    	if (mNiNotification == null) {
-        	mNiNotification = new Notification();
-        	mNiNotification.icon = com.android.internal.R.drawable.stat_sys_gps_on; /* Change notification icon here */
-        	mNiNotification.when = 0;
+                ", title: " + title +
+                ", message: " + message);
+
+        // Construct Notification
+        if (mNiNotification == null) {
+            mNiNotification = new Notification();
+            mNiNotification.icon = com.android.internal.R.drawable.stat_sys_gps_on; /* Change notification icon here */
+            mNiNotification.when = 0;
         }
-    	
+
         if (mPlaySounds) {
-        	mNiNotification.defaults |= Notification.DEFAULT_SOUND;
+            mNiNotification.defaults |= Notification.DEFAULT_SOUND;
         } else {
-        	mNiNotification.defaults &= ~Notification.DEFAULT_SOUND;
+            mNiNotification.defaults &= ~Notification.DEFAULT_SOUND;
         }        
-        
+
         mNiNotification.flags = Notification.FLAG_ONGOING_EVENT;
         mNiNotification.tickerText = getNotifTicker(notif);
-        
+
         // if not to popup dialog immediately, pending intent will open the dialog
-        Intent intent = !mPopupImmediately ? getDlgIntent(notif) : new Intent();    	        
+        Intent intent = !mPopupImmediately ? getDlgIntent(notif) : new Intent();
         PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);                
         mNiNotification.setLatestEventInfo(mContext, title, message, pi);
-        
+
         if (visible) {
             notificationManager.notify(notif.notificationId, mNiNotification);
         } else {
             notificationManager.cancel(notif.notificationId);
         }
     }
-    
-    // Opens the notification dialog and waits for user input
-    private void openNiDialog(GpsNiNotification notif) 
-    {
-    	Intent intent = getDlgIntent(notif);
-    	
-    	if (DEBUG) Log.d(TAG, "openNiDialog, notifyId: " + notif.notificationId + 
-    			", requestorId: " + notif.requestorId + 
-    			", text: " + notif.text);               	
 
-    	mContext.startActivity(intent);
+    // Opens the notification dialog and waits for user input
+    private void openNiDialog(GpsNiNotification notif)
+    {
+        Intent intent = getDlgIntent(notif);
+
+        if (DEBUG) Log.d(TAG, "openNiDialog, notifyId: " + notif.notificationId +
+                ", requestorId: " + notif.requestorId +
+                ", text: " + notif.text);
+
+        mContext.startActivity(intent);
     }
-    
+
     // Construct the intent for bringing up the dialog activity, which shows the 
     // notification and takes user input
     private Intent getDlgIntent(GpsNiNotification notif)
     {
-    	Intent intent = new Intent();
-    	String title = getDialogTitle(notif);
-    	String message = getDialogMessage(notif);
-    	
-    	// directly bring up the NI activity
-    	intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-    	intent.setClass(mContext, com.android.internal.app.NetInitiatedActivity.class);    	
+        Intent intent = new Intent();
+        String title = getDialogTitle(notif);
+        String message = getDialogMessage(notif);
 
-    	// put data in the intent
-    	intent.putExtra(NI_INTENT_KEY_NOTIF_ID, notif.notificationId);    	
-    	intent.putExtra(NI_INTENT_KEY_TITLE, title);
-    	intent.putExtra(NI_INTENT_KEY_MESSAGE, message);
-    	intent.putExtra(NI_INTENT_KEY_TIMEOUT, notif.timeout);
-    	intent.putExtra(NI_INTENT_KEY_DEFAULT_RESPONSE, notif.defaultResponse);
-    	
-    	if (DEBUG) Log.d(TAG, "generateIntent, title: " + title + ", message: " + message +
-    			", timeout: " + notif.timeout);
-    	
-    	return intent;
+        // directly bring up the NI activity
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setClass(mContext, com.android.internal.app.NetInitiatedActivity.class);
+
+        // put data in the intent
+        intent.putExtra(NI_INTENT_KEY_NOTIF_ID, notif.notificationId);
+        intent.putExtra(NI_INTENT_KEY_TITLE, title);
+        intent.putExtra(NI_INTENT_KEY_MESSAGE, message);
+        intent.putExtra(NI_INTENT_KEY_TIMEOUT, notif.timeout);
+        intent.putExtra(NI_INTENT_KEY_DEFAULT_RESPONSE, notif.defaultResponse);
+
+        if (DEBUG) Log.d(TAG, "generateIntent, title: " + title + ", message: " + message +
+                ", timeout: " + notif.timeout);
+
+        return intent;
     }
-    
+
     // Converts a string (or Hex string) to a char array
     static byte[] stringToByteArray(String original, boolean isHex)
     {
-    	int length = isHex ? original.length() / 2 : original.length();
-    	byte[] output = new byte[length];
-    	int i;
-    	
-    	if (isHex)
-    	{
-    		for (i = 0; i < length; i++)
-    		{
-    			output[i] = (byte) Integer.parseInt(original.substring(i*2, i*2+2), 16);
-    		}
-    	}
-    	else {
-    		for (i = 0; i < length; i++)
-    		{
-    			output[i] = (byte) original.charAt(i);
-    		}
-    	}
-    	
-    	return output;
+        int length = isHex ? original.length() / 2 : original.length();
+        byte[] output = new byte[length];
+        int i;
+
+        if (isHex)
+        {
+            for (i = 0; i < length; i++)
+            {
+                output[i] = (byte) Integer.parseInt(original.substring(i*2, i*2+2), 16);
+            }
+        }
+        else {
+            for (i = 0; i < length; i++)
+            {
+                output[i] = (byte) original.charAt(i);
+            }
+        }
+
+        return output;
     }
-    
+
     /**
      * Unpacks an byte array containing 7-bit packed characters into a String.
-     * 
+     *
      * @param input a 7-bit packed char array
      * @return the unpacked String
      */
     static String decodeGSMPackedString(byte[] input)
     {
-    	final char CHAR_CR = 0x0D;
-    	int nStridx = 0;
-    	int nPckidx = 0;
-    	int num_bytes = input.length;
-    	int cPrev = 0;
-    	int cCurr = 0;
-    	byte nShift;
-    	byte nextChar;
-    	byte[] stringBuf = new byte[input.length * 2]; 
-    	String result = "";
-    	
-    	while(nPckidx < num_bytes)
-    	{
-    		nShift = (byte) (nStridx & 0x07);
-    		cCurr = input[nPckidx++];
-    		if (cCurr < 0) cCurr += 256;
+        final char CHAR_CR = 0x0D;
+        int nStridx = 0;
+        int nPckidx = 0;
+        int num_bytes = input.length;
+        int cPrev = 0;
+        int cCurr = 0;
+        byte nShift;
+        byte nextChar;
+        byte[] stringBuf = new byte[input.length * 2];
+        String result = "";
 
-    		/* A 7-bit character can be split at the most between two bytes of packed
-    		 ** data.
-    		 */
-    		nextChar = (byte) (( (cCurr << nShift) | (cPrev >> (8-nShift)) ) & 0x7F);
-    		stringBuf[nStridx++] = nextChar;
+        while(nPckidx < num_bytes)
+        {
+            nShift = (byte) (nStridx & 0x07);
+            cCurr = input[nPckidx++];
+            if (cCurr < 0) cCurr += 256;
 
-    		/* Special case where the whole of the next 7-bit character fits inside
-    		 ** the current byte of packed data.
-    		 */
-    		if(nShift == 6)
-    		{
-    			/* If the next 7-bit character is a CR (0x0D) and it is the last
-    			 ** character, then it indicates a padding character. Drop it.
-    			 */
-    			if (nPckidx == num_bytes || (cCurr >> 1) == CHAR_CR)
-    			{
-    				break;
-    			}
-    			
-    			nextChar = (byte) (cCurr >> 1); 
-    			stringBuf[nStridx++] = nextChar;
-    		}
+            /* A 7-bit character can be split at the most between two bytes of packed
+             ** data.
+             */
+            nextChar = (byte) (( (cCurr << nShift) | (cPrev >> (8-nShift)) ) & 0x7F);
+            stringBuf[nStridx++] = nextChar;
 
-    		cPrev = cCurr;
-    	}
-    	
-    	try{
-    		result = new String(stringBuf, 0, nStridx, "US-ASCII");
-    	}
-    	catch (UnsupportedEncodingException e)
-    	{
-    		Log.e(TAG, e.getMessage());
-    	}
-    	
-    	return result;
+            /* Special case where the whole of the next 7-bit character fits inside
+             ** the current byte of packed data.
+             */
+            if(nShift == 6)
+            {
+                /* If the next 7-bit character is a CR (0x0D) and it is the last
+                 ** character, then it indicates a padding character. Drop it.
+                 */
+                if (nPckidx == num_bytes || (cCurr >> 1) == CHAR_CR)
+                {
+                    break;
+                }
+
+                nextChar = (byte) (cCurr >> 1);
+                stringBuf[nStridx++] = nextChar;
+            }
+
+            cPrev = cCurr;
+        }
+
+        try {
+            result = new String(stringBuf, 0, nStridx, "US-ASCII");
+        }
+        catch (UnsupportedEncodingException e)
+        {
+            Log.e(TAG, e.getMessage());
+        }
+
+        return result;
     }
-    
+
     static String decodeUTF8String(byte[] input)
     {
-    	String decoded = "";
-    	try {
-    		decoded = new String(input, "UTF-8");
-    	}
-    	catch (UnsupportedEncodingException e)
-    	{ 
-    		Log.e(TAG, e.getMessage());
-    	} 
-		return decoded;
+        String decoded = "";
+        try {
+            decoded = new String(input, "UTF-8");
+        }
+        catch (UnsupportedEncodingException e)
+        {
+            Log.e(TAG, e.getMessage());
+        }
+        return decoded;
     }
-    
+
     static String decodeUCS2String(byte[] input)
     {
-    	String decoded = "";
-    	try {
-    		decoded = new String(input, "UTF-16");
-    	}
-    	catch (UnsupportedEncodingException e)
-    	{ 
-    		Log.e(TAG, e.getMessage());
-    	} 
-		return decoded;
+        String decoded = "";
+        try {
+            decoded = new String(input, "UTF-16");
+        }
+        catch (UnsupportedEncodingException e)
+        {
+            Log.e(TAG, e.getMessage());
+        }
+        return decoded;
     }
-    
+
     /** Decode NI string
-     * 
+     *
      * @param original   The text string to be decoded
      * @param isHex      Specifies whether the content of the string has been encoded as a Hex string. Encoding
-     *                   a string as Hex can allow zeros inside the coded text. 
+     *                   a string as Hex can allow zeros inside the coded text.
      * @param coding     Specifies the coding scheme of the string, such as GSM, UTF8, UCS2, etc. This coding scheme
-     * 					 needs to match those used passed to HAL from the native GPS driver. Decoding is done according
+     *                      needs to match those used passed to HAL from the native GPS driver. Decoding is done according
      *                   to the <code> coding </code>, after a Hex string is decoded. Generally, if the
-     *                   notification strings don't need further decoding, <code> coding </code> encoding can be 
+     *                   notification strings don't need further decoding, <code> coding </code> encoding can be
      *                   set to -1, and <code> isHex </code> can be false.
      * @return the decoded string
      */
     static private String decodeString(String original, boolean isHex, int coding)
     {
-    	String decoded = original;
-    	byte[] input = stringToByteArray(original, isHex);
+        String decoded = original;
+        byte[] input = stringToByteArray(original, isHex);
 
-    	switch (coding) {
-    	case GPS_ENC_NONE:
-    		decoded = original;
-    		break;
-    		
-    	case GPS_ENC_SUPL_GSM_DEFAULT:
-    		decoded = decodeGSMPackedString(input);
-    		break;
-    		
-    	case GPS_ENC_SUPL_UTF8:
-    		decoded = decodeUTF8String(input);
-    		break;
-    		
-    	case GPS_ENC_SUPL_UCS2:
-    		decoded = decodeUCS2String(input);
-    		break;
-    		
-    	case GPS_ENC_UNKNOWN:
-    		decoded = original;
-    		break;
-    		
-    	default:
-    		Log.e(TAG, "Unknown encoding " + coding + " for NI text " + original);
-    		break;
-    	}
-    	return decoded;
+        switch (coding) {
+        case GPS_ENC_NONE:
+            decoded = original;
+            break;
+
+        case GPS_ENC_SUPL_GSM_DEFAULT:
+            decoded = decodeGSMPackedString(input);
+            break;
+
+        case GPS_ENC_SUPL_UTF8:
+            decoded = decodeUTF8String(input);
+            break;
+
+        case GPS_ENC_SUPL_UCS2:
+            decoded = decodeUCS2String(input);
+            break;
+
+        case GPS_ENC_UNKNOWN:
+            decoded = original;
+            break;
+
+        default:
+            Log.e(TAG, "Unknown encoding " + coding + " for NI text " + original);
+            break;
+        }
+        return decoded;
     }
-    
+
     // change this to configure notification display
     static private String getNotifTicker(GpsNiNotification notif)
     {
-    	String ticker = String.format("Position request! ReqId: [%s] ClientName: [%s]",
-    			decodeString(notif.requestorId, mIsHexInput, notif.requestorIdEncoding),
-    			decodeString(notif.text, mIsHexInput, notif.textEncoding));
-    	return ticker;
+        String ticker = String.format("Position request! ReqId: [%s] ClientName: [%s]",
+                decodeString(notif.requestorId, mIsHexInput, notif.requestorIdEncoding),
+                decodeString(notif.text, mIsHexInput, notif.textEncoding));
+        return ticker;
     }
-    
+
     // change this to configure notification display
     static private String getNotifTitle(GpsNiNotification notif)
     {
-    	String title = String.format("Position Request");
-    	return title;
+        String title = String.format("Position Request");
+        return title;
     }
-    
+
     // change this to configure notification display
     static private String getNotifMessage(GpsNiNotification notif)
     {
-    	String message = String.format(
-    			"NI Request received from [%s] for client [%s]!", 
-    			decodeString(notif.requestorId, mIsHexInput, notif.requestorIdEncoding),
-    			decodeString(notif.text, mIsHexInput, notif.textEncoding));
-    	return message;
+        String message = String.format(
+                "NI Request received from [%s] for client [%s]!",
+                decodeString(notif.requestorId, mIsHexInput, notif.requestorIdEncoding),
+                decodeString(notif.text, mIsHexInput, notif.textEncoding));
+        return message;
     }       
-    
+
     // change this to configure dialog display (for verification)
     static public String getDialogTitle(GpsNiNotification notif)
     {
-    	return getNotifTitle(notif);
+        return getNotifTitle(notif);
     }
-    
+
     // change this to configure dialog display (for verification)
     static private String getDialogMessage(GpsNiNotification notif)
     {
-    	return getNotifMessage(notif);
+        return getNotifMessage(notif);
     }
-    
+
 }
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 47a1ec3..930a053 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1518,4 +1518,22 @@
       * {@hide}
       */
      private IBinder mICallBack = new Binder();
+
+    /**
+     * Checks whether the phone is in silent mode, with or without vibrate.
+     *
+     * @return true if phone is in silent mode, with or without vibrate.
+     *
+     * @see #getRingerMode()
+     *
+     * @hide pending API Council approval
+     */
+    public boolean isSilentMode() {
+        int ringerMode = getRingerMode();
+        boolean silentMode =
+            (ringerMode == RINGER_MODE_SILENT) ||
+            (ringerMode == RINGER_MODE_VIBRATE);
+        return silentMode;
+    }
+
 }
diff --git a/opengl/tests/testViewport/Android.mk b/opengl/tests/testViewport/Android.mk
new file mode 100644
index 0000000..3da59b5
--- /dev/null
+++ b/opengl/tests/testViewport/Android.mk
@@ -0,0 +1,22 @@
+#########################################################################
+# OpenGL ES JNI sample
+# This makefile builds both an activity and a shared library.
+#########################################################################
+ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean
+
+TOP_LOCAL_PATH:= $(call my-dir)
+
+# Build activity
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := TestViewport
+
+include $(BUILD_PACKAGE)
+
+endif # TARGET_SIMULATOR
diff --git a/opengl/tests/testViewport/AndroidManifest.xml b/opengl/tests/testViewport/AndroidManifest.xml
new file mode 100644
index 0000000..f4a493e
--- /dev/null
+++ b/opengl/tests/testViewport/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2009, 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.
+*/
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.test">
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <application
+            android:label="@string/test_activity">
+        <activity android:name="TestActivity"
+                android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+            	android:configChanges="orientation|keyboardHidden">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/opengl/tests/testViewport/README b/opengl/tests/testViewport/README
new file mode 100644
index 0000000..c06abc9
--- /dev/null
+++ b/opengl/tests/testViewport/README
@@ -0,0 +1,28 @@
+Repro steps:
+
+build, install and run the attached test program TestViewport.apk
+
+Run on Sapphire with Froyo.
+
+The program clears the screen to blue, then draws a full screen white quad that
+is alligned to the screen.
+(Therefore the whole screen should appear to be white.)
+
+
+Note that screen is all white.
+
+Rotate screen 90 degrees.
+
+Expected: screen is still all white.
+
+Actual: screen is blue with offset white rectangle.
+
+This bug only happens on Sapphire, it works correctly on Passion.
+
+What happens:
+
+I think the bug is that the gl.glViewport() call in onSurfaceChanged() is
+being ignored by the OpenGL driver.
+
+NOTE: If a gl.glViewport call is added at the beginning of the onDrawFrame()
+call (which means it is called before every draw), the program runs correctly.
diff --git a/opengl/tests/testViewport/res/values/strings.xml b/opengl/tests/testViewport/res/values/strings.xml
new file mode 100644
index 0000000..f4b8bbb
--- /dev/null
+++ b/opengl/tests/testViewport/res/values/strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<!-- This file contains resource definitions for displayed strings, allowing
+     them to be changed based on the locale and options. -->
+
+<resources>
+    <!-- Simple strings. -->
+    <string name="test_activity">Test Viewport</string>
+
+</resources>
+
diff --git a/opengl/tests/testViewport/src/com/android/test/TestActivity.java b/opengl/tests/testViewport/src/com/android/test/TestActivity.java
new file mode 100644
index 0000000..cc7e450
--- /dev/null
+++ b/opengl/tests/testViewport/src/com/android/test/TestActivity.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2007 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.test;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+public class TestActivity extends Activity {
+    private final static String TAG = "TestActivity";
+    TestView mView;
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        mView = new TestView(getApplication());
+	    mView.setFocusableInTouchMode(true);
+	    setContentView(mView);
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        mView.onPause();
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mView.onResume();
+    }
+}
diff --git a/opengl/tests/testViewport/src/com/android/test/TestView.java b/opengl/tests/testViewport/src/com/android/test/TestView.java
new file mode 100644
index 0000000..23cc37d
--- /dev/null
+++ b/opengl/tests/testViewport/src/com/android/test/TestView.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2009 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.test;
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.FloatBuffer;
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL;
+import javax.microedition.khronos.opengles.GL10;
+import javax.microedition.khronos.opengles.GL11;
+/**
+ * An implementation of SurfaceView that uses the dedicated surface for
+ * displaying an OpenGL animation.  This allows the animation to run in a
+ * separate thread, without requiring that it be driven by the update mechanism
+ * of the view hierarchy.
+ *
+ * The application-specific rendering code is delegated to a GLView.Renderer
+ * instance.
+ */
+class TestView extends GLSurfaceView {
+    TestView(Context context) {
+        super(context);
+        init();
+    }
+
+    public TestView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    private void init() {
+        setRenderer(new Renderer());
+        setRenderMode(RENDERMODE_WHEN_DIRTY);
+    }
+    
+        /** A grid is a topologically rectangular array of vertices.
+    *
+    * The vertex and index data are held in VBO objects because on most
+    * GPUs VBO objects are the fastest way of rendering static vertex
+    * and index data.
+    *
+    */
+
+   private static class Grid {
+       // Size of vertex data elements in bytes:
+       final static int FLOAT_SIZE = 4;
+       final static int CHAR_SIZE = 2;
+
+       // Vertex structure:
+       // float x, y, z;
+
+       final static int VERTEX_SIZE = 3 * FLOAT_SIZE;
+
+       private int mVertexBufferObjectId;
+       private int mElementBufferObjectId;
+
+       // These buffers are used to hold the vertex and index data while
+       // constructing the grid. Once createBufferObjects() is called
+       // the buffers are nulled out to save memory.
+
+       private ByteBuffer mVertexByteBuffer;
+       private FloatBuffer mVertexBuffer;
+       private CharBuffer mIndexBuffer;
+
+       private int mW;
+       private int mH;
+       private int mIndexCount;
+
+       public Grid(int w, int h) {
+           if (w < 0 || w >= 65536) {
+               throw new IllegalArgumentException("w");
+           }
+           if (h < 0 || h >= 65536) {
+               throw new IllegalArgumentException("h");
+           }
+           if (w * h >= 65536) {
+               throw new IllegalArgumentException("w * h >= 65536");
+           }
+
+           mW = w;
+           mH = h;
+           int size = w * h;
+
+           mVertexByteBuffer = ByteBuffer.allocateDirect(VERTEX_SIZE * size)
+               .order(ByteOrder.nativeOrder());
+           mVertexBuffer = mVertexByteBuffer.asFloatBuffer();
+
+           int quadW = mW - 1;
+           int quadH = mH - 1;
+           int quadCount = quadW * quadH;
+           int indexCount = quadCount * 6;
+           mIndexCount = indexCount;
+           mIndexBuffer = ByteBuffer.allocateDirect(CHAR_SIZE * indexCount)
+               .order(ByteOrder.nativeOrder()).asCharBuffer();
+
+           /*
+            * Initialize triangle list mesh.
+            *
+            *     [0]-----[  1] ...
+            *      |    /   |
+            *      |   /    |
+            *      |  /     |
+            *     [w]-----[w+1] ...
+            *      |       |
+            *
+            */
+
+           {
+               int i = 0;
+               for (int y = 0; y < quadH; y++) {
+                   for (int x = 0; x < quadW; x++) {
+                       char a = (char) (y * mW + x);
+                       char b = (char) (y * mW + x + 1);
+                       char c = (char) ((y + 1) * mW + x);
+                       char d = (char) ((y + 1) * mW + x + 1);
+
+                       mIndexBuffer.put(i++, a);
+                       mIndexBuffer.put(i++, c);
+                       mIndexBuffer.put(i++, b);
+
+                       mIndexBuffer.put(i++, b);
+                       mIndexBuffer.put(i++, c);
+                       mIndexBuffer.put(i++, d);
+                   }
+               }
+           }
+
+       }
+
+       public void set(int i, int j, float x, float y, float z) {
+           if (i < 0 || i >= mW) {
+               throw new IllegalArgumentException("i");
+           }
+           if (j < 0 || j >= mH) {
+               throw new IllegalArgumentException("j");
+           }
+
+           int index = mW * j + i;
+
+           mVertexBuffer.position(index * VERTEX_SIZE / FLOAT_SIZE);
+           mVertexBuffer.put(x);
+           mVertexBuffer.put(y);
+           mVertexBuffer.put(z);
+       }
+
+       public void createBufferObjects(GL gl) {
+           // Generate a the vertex and element buffer IDs
+           int[] vboIds = new int[2];
+           GL11 gl11 = (GL11) gl;
+           gl11.glGenBuffers(2, vboIds, 0);
+           mVertexBufferObjectId = vboIds[0];
+           mElementBufferObjectId = vboIds[1];
+
+           // Upload the vertex data
+           gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertexBufferObjectId);
+           mVertexByteBuffer.position(0);
+           gl11.glBufferData(GL11.GL_ARRAY_BUFFER, mVertexByteBuffer.capacity(), mVertexByteBuffer, GL11.GL_STATIC_DRAW);
+
+           gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mElementBufferObjectId);
+           mIndexBuffer.position(0);
+           gl11.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer.capacity() * CHAR_SIZE, mIndexBuffer, GL11.GL_STATIC_DRAW);
+
+           // We don't need the in-memory data any more
+           mVertexBuffer = null;
+           mVertexByteBuffer = null;
+           mIndexBuffer = null;
+       }
+
+       public void draw(GL10 gl) {
+           GL11 gl11 = (GL11) gl;
+
+           gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
+
+           gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertexBufferObjectId);
+           gl11.glVertexPointer(3, GL10.GL_FLOAT, VERTEX_SIZE, 0);
+           
+           gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mElementBufferObjectId);
+           gl11.glDrawElements(GL10.GL_TRIANGLES, mIndexCount, GL10.GL_UNSIGNED_SHORT, 0);
+           gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
+           gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
+           gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
+       }
+   }
+
+
+    private class Renderer implements GLSurfaceView.Renderer {
+        private static final String TAG = "Renderer";
+        private Grid mGrid;
+        
+        public void onDrawFrame(GL10 gl) {
+			gl.glClearColor(0,0,1,1);
+			gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
+            mGrid.draw(gl);
+        }
+
+        public void onSurfaceChanged(GL10 gl, int width, int height) {
+            gl.glViewport(0, 0, width, height);
+			gl.glMatrixMode(GL11.GL_PROJECTION);
+			gl.glLoadIdentity();
+			gl.glOrthof(0, width, height, 0, -1, 1);
+			gl.glMatrixMode(GL11.GL_MODELVIEW);
+            createGrid(gl, width, height);
+        }
+
+        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+        }
+        
+        private void createGrid(GL10 gl, float w, float h) {
+        mGrid = new Grid(2, 2);
+			for (int j = 0; j < 2; j++) {
+				for (int i = 0; i < 2; i++) {
+					float x = w * i;
+					float y = h * j;
+					float z = 0.0f;
+					mGrid.set(i,j, x, y, z);
+				}
+			}
+			mGrid.createBufferObjects(gl);
+		}
+    }
+}
+
diff --git a/preloaded-classes b/preloaded-classes
index 54c7303..5d2fd68 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -269,7 +269,6 @@
 android.location.ILocationManager$Stub$Proxy
 android.location.Location
 android.location.LocationManager
-android.location.LocationProviderInterface
 android.media.AudioFormat
 android.media.AudioManager
 android.media.AudioRecord
@@ -633,7 +632,6 @@
 com.android.internal.content.SyncStateContentProviderHelper
 com.android.internal.graphics.NativeUtils
 com.android.internal.location.DummyLocationProvider
-com.android.internal.location.GpsLocationProvider
 com.android.internal.logging.AndroidHandler
 com.android.internal.os.AndroidPrintStream
 com.android.internal.os.BinderInternal
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index ef57056..b92480f 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -16,17 +16,6 @@
 
 package com.android.server;
 
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Observable;
-import java.util.Observer;
-import java.util.Set;
-
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -50,7 +39,6 @@
 import android.location.Location;
 import android.location.LocationManager;
 import android.location.LocationProvider;
-import android.location.LocationProviderInterface;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.Uri;
@@ -68,12 +56,25 @@
 import android.util.Slog;
 import android.util.PrintWriterPrinter;
 
-import com.android.internal.location.GeocoderProxy;
-import com.android.internal.location.GpsLocationProvider;
 import com.android.internal.location.GpsNetInitiatedHandler;
-import com.android.internal.location.LocationProviderProxy;
-import com.android.internal.location.MockProvider;
-import com.android.internal.location.PassiveProvider;
+
+import com.android.server.location.GeocoderProxy;
+import com.android.server.location.GpsLocationProvider;
+import com.android.server.location.LocationProviderInterface;
+import com.android.server.location.LocationProviderProxy;
+import com.android.server.location.MockProvider;
+import com.android.server.location.PassiveProvider;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Observable;
+import java.util.Observer;
+import java.util.Set;
 
 /**
  * The service class that manages LocationProviders and issues location
@@ -461,10 +462,11 @@
         mEnabledProviders.add(passiveProvider.getName());
 
         // initialize external network location and geocoder services
+        PackageManager pm = mContext. getPackageManager();
         Resources resources = mContext.getResources();
         String serviceName = resources.getString(
                 com.android.internal.R.string.config_networkLocationProvider);
-        if (serviceName != null) {
+        if (serviceName != null && pm.resolveService(new Intent(serviceName), 0) != null) {
             mNetworkLocationProvider =
                 new LocationProviderProxy(mContext, LocationManager.NETWORK_PROVIDER,
                         serviceName, mLocationHandler);
@@ -472,7 +474,7 @@
         }
 
         serviceName = resources.getString(com.android.internal.R.string.config_geocodeProvider);
-        if (serviceName != null) {
+        if (serviceName != null && pm.resolveService(new Intent(serviceName), 0) != null) {
             mGeocodeProvider = new GeocoderProxy(mContext, serviceName);
         }
 
diff --git a/location/java/com/android/internal/location/GeocoderProxy.java b/services/java/com/android/server/location/GeocoderProxy.java
similarity index 98%
rename from location/java/com/android/internal/location/GeocoderProxy.java
rename to services/java/com/android/server/location/GeocoderProxy.java
index b06297b..3c05da2 100644
--- a/location/java/com/android/internal/location/GeocoderProxy.java
+++ b/services/java/com/android/server/location/GeocoderProxy.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.location;
+package com.android.server.location;
 
 import android.content.ComponentName;
 import android.content.Context;
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
similarity index 96%
rename from location/java/com/android/internal/location/GpsLocationProvider.java
rename to services/java/com/android/server/location/GpsLocationProvider.java
index 15d692c..daa198f 100755
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.location;
+package com.android.server.location;
 
 import android.app.AlarmManager;
 import android.app.PendingIntent;
@@ -30,7 +30,6 @@
 import android.location.Location;
 import android.location.LocationManager;
 import android.location.LocationProvider;
-import android.location.LocationProviderInterface;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.SntpClient;
@@ -77,37 +76,6 @@
     private static final boolean DEBUG = false;
     private static final boolean VERBOSE = false;
 
-    /**
-     * Broadcast intent action indicating that the GPS has either been
-     * enabled or disabled. An intent extra provides this state as a boolean,
-     * where {@code true} means enabled.
-     * @see #EXTRA_ENABLED
-     *
-     * {@hide}
-     */
-    public static final String GPS_ENABLED_CHANGE_ACTION =
-        "android.location.GPS_ENABLED_CHANGE";
-
-    /**
-     * Broadcast intent action indicating that the GPS has either started or
-     * stopped receiving GPS fixes. An intent extra provides this state as a
-     * boolean, where {@code true} means that the GPS is actively receiving fixes.
-     * @see #EXTRA_ENABLED
-     *
-     * {@hide}
-     */
-    public static final String GPS_FIX_CHANGE_ACTION =
-        "android.location.GPS_FIX_CHANGE";
-
-    /**
-     * The lookup key for a boolean that indicates whether GPS is enabled or
-     * disabled. {@code true} means GPS is enabled. Retrieve it with
-     * {@link android.content.Intent#getBooleanExtra(String,boolean)}.
-     *
-     * {@hide}
-     */
-    public static final String EXTRA_ENABLED = "enabled";
-
     // these need to match GpsPositionMode enum in gps.h
     private static final int GPS_POSITION_MODE_STANDALONE = 0;
     private static final int GPS_POSITION_MODE_MS_BASED = 1;
@@ -348,7 +316,7 @@
     public GpsLocationProvider(Context context, ILocationManager locationManager) {
         mContext = context;
         mLocationManager = locationManager;
-        mNIHandler = new GpsNetInitiatedHandler(context, this);
+        mNIHandler = new GpsNetInitiatedHandler(context);
 
         mLocation.setExtras(mLocationExtras);
 
@@ -1031,8 +999,8 @@
             }
 
             // send an intent to notify that the GPS is receiving fixes.
-            Intent intent = new Intent(GPS_FIX_CHANGE_ACTION);
-            intent.putExtra(EXTRA_ENABLED, true);
+            Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
+            intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
             mContext.sendBroadcast(intent);
             updateStatus(LocationProvider.AVAILABLE, mSvCount);
         }
@@ -1108,8 +1076,8 @@
                 }
 
                 // send an intent to notify that the GPS has been enabled or disabled.
-                Intent intent = new Intent(GPS_ENABLED_CHANGE_ACTION);
-                intent.putExtra(EXTRA_ENABLED, mNavigating);
+                Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
+                intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
                 mContext.sendBroadcast(intent);
             }
 
@@ -1165,8 +1133,8 @@
         if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
             System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT * 1000) {
             // send an intent to notify that the GPS is no longer receiving fixes.
-            Intent intent = new Intent(GPS_FIX_CHANGE_ACTION);
-            intent.putExtra(EXTRA_ENABLED, false);
+            Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
+            intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
             mContext.sendBroadcast(intent);
             updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount);
         }
diff --git a/location/java/com/android/internal/location/GpsXtraDownloader.java b/services/java/com/android/server/location/GpsXtraDownloader.java
similarity index 98%
rename from location/java/com/android/internal/location/GpsXtraDownloader.java
rename to services/java/com/android/server/location/GpsXtraDownloader.java
index 978bda2..bc96980 100644
--- a/location/java/com/android/internal/location/GpsXtraDownloader.java
+++ b/services/java/com/android/server/location/GpsXtraDownloader.java
@@ -14,7 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.internal.location;
+package com.android.server.location;
+
+import android.content.Context;
+import android.net.Proxy;
+import android.net.http.AndroidHttpClient;
+import android.util.Config;
+import android.util.Log;
 
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpHost;
@@ -30,14 +36,6 @@
 import java.util.Properties;
 import java.util.Random;
 
-import android.content.Context;
-import android.net.Proxy;
-import android.net.http.AndroidHttpClient;
-import android.util.Config;
-import android.util.Log;
-
-
-
 /**
  * A class for downloading GPS XTRA data.
  *
diff --git a/location/java/android/location/LocationProviderInterface.java b/services/java/com/android/server/location/LocationProviderInterface.java
similarity index 97%
rename from location/java/android/location/LocationProviderInterface.java
rename to services/java/com/android/server/location/LocationProviderInterface.java
index 5ffe15c3..a472143 100644
--- a/location/java/android/location/LocationProviderInterface.java
+++ b/services/java/com/android/server/location/LocationProviderInterface.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.location;
+package com.android.server.location;
 
 import android.location.Location;
 import android.net.NetworkInfo;
diff --git a/location/java/com/android/internal/location/LocationProviderProxy.java b/services/java/com/android/server/location/LocationProviderProxy.java
similarity index 98%
rename from location/java/com/android/internal/location/LocationProviderProxy.java
rename to services/java/com/android/server/location/LocationProviderProxy.java
index 31ec09a..3e118f9 100644
--- a/location/java/com/android/internal/location/LocationProviderProxy.java
+++ b/services/java/com/android/server/location/LocationProviderProxy.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.location;
+package com.android.server.location;
 
 import android.content.ComponentName;
 import android.content.Context;
@@ -22,7 +22,6 @@
 import android.content.ServiceConnection;
 import android.location.ILocationProvider;
 import android.location.Location;
-import android.location.LocationProviderInterface;
 import android.net.NetworkInfo;
 import android.os.Bundle;
 import android.os.Handler;
@@ -31,6 +30,8 @@
 import android.os.SystemClock;
 import android.util.Log;
 
+import com.android.internal.location.DummyLocationProvider;
+
 /**
  * A class for proxying location providers implemented as services.
  *
diff --git a/location/java/com/android/internal/location/MockProvider.java b/services/java/com/android/server/location/MockProvider.java
similarity index 97%
rename from location/java/com/android/internal/location/MockProvider.java
rename to services/java/com/android/server/location/MockProvider.java
index d912740..e3f33469 100644
--- a/location/java/com/android/internal/location/MockProvider.java
+++ b/services/java/com/android/server/location/MockProvider.java
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.internal.location;
+package com.android.server.location;
 
 import android.location.ILocationManager;
 import android.location.Location;
 import android.location.LocationProvider;
-import android.location.LocationProviderInterface;
 import android.net.NetworkInfo;
 import android.os.Bundle;
 import android.os.RemoteException;
diff --git a/location/java/com/android/internal/location/PassiveProvider.java b/services/java/com/android/server/location/PassiveProvider.java
similarity index 96%
rename from location/java/com/android/internal/location/PassiveProvider.java
rename to services/java/com/android/server/location/PassiveProvider.java
index ab90937..5ed1558 100644
--- a/location/java/com/android/internal/location/PassiveProvider.java
+++ b/services/java/com/android/server/location/PassiveProvider.java
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.internal.location;
+package com.android.server.location;
 
 import android.location.ILocationManager;
 import android.location.Location;
 import android.location.LocationManager;
 import android.location.LocationProvider;
-import android.location.LocationProviderInterface;
 import android.net.NetworkInfo;
 import android.os.Bundle;
 import android.os.RemoteException;
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index 55840e2..efb1a06 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -30,6 +30,7 @@
 import android.content.res.TypedArray;
 import android.graphics.PixelFormat;
 import android.graphics.drawable.Drawable;
+import android.location.LocationManager;
 import android.media.AudioManager;
 import android.media.Ringtone;
 import android.media.RingtoneManager;
@@ -62,7 +63,6 @@
 
 import com.android.internal.R;
 import com.android.internal.app.IBatteryStats;
-import com.android.internal.location.GpsLocationProvider;
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.cdma.EriInfo;
@@ -387,8 +387,8 @@
                     action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
                 updateWifi(intent);
             }
-            else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) ||
-                    action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION)) {
+            else if (action.equals(LocationManager.GPS_ENABLED_CHANGE_ACTION) ||
+                    action.equals(LocationManager.GPS_FIX_CHANGE_ACTION)) {
                 updateGps(intent);
             }
             else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) ||
@@ -533,8 +533,8 @@
         filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
         filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
         filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
-        filter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION);
-        filter.addAction(GpsLocationProvider.GPS_FIX_CHANGE_ACTION);
+        filter.addAction(LocationManager.GPS_ENABLED_CHANGE_ACTION);
+        filter.addAction(LocationManager.GPS_FIX_CHANGE_ACTION);
         filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
         filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
         mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
@@ -1286,13 +1286,13 @@
 
     private final void updateGps(Intent intent) {
         final String action = intent.getAction();
-        final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, false);
+        final boolean enabled = intent.getBooleanExtra(LocationManager.EXTRA_GPS_ENABLED, false);
 
-        if (action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION) && enabled) {
+        if (action.equals(LocationManager.GPS_FIX_CHANGE_ACTION) && enabled) {
             // GPS is getting fixes
             mService.updateIcon(mGpsIcon, mGpsFixIconData, null);
             mService.setIconVisibility(mGpsIcon, true);
-        } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) && !enabled) {
+        } else if (action.equals(LocationManager.GPS_ENABLED_CHANGE_ACTION) && !enabled) {
             // GPS is off
             mService.setIconVisibility(mGpsIcon, false);
         } else {
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index 9d2760e..b90e327 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -9,6 +9,7 @@
     com_android_server_SensorService.cpp \
     com_android_server_SystemServer.cpp \
     com_android_server_VibratorService.cpp \
+	com_android_server_location_GpsLocationProvider.cpp \
     onload.cpp
 
 LOCAL_C_INCLUDES += \
diff --git a/core/jni/android_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp
similarity index 94%
rename from core/jni/android_location_GpsLocationProvider.cpp
rename to services/jni/com_android_server_location_GpsLocationProvider.cpp
index a3be309..1823621 100755
--- a/core/jni/android_location_GpsLocationProvider.cpp
+++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -41,6 +41,7 @@
 static const GpsInterface* sGpsInterface = NULL;
 static const GpsXtraInterface* sGpsXtraInterface = NULL;
 static const AGpsInterface* sAGpsInterface = NULL;
+static const GpsPrivacyInterface* sGpsPrivacyInterface = NULL;
 static const GpsNiInterface* sGpsNiInterface = NULL;
 static const GpsDebugInterface* sGpsDebugInterface = NULL;
 
@@ -223,9 +224,15 @@
         sAGpsInterface->init(&sAGpsCallbacks);
 
     if (!sGpsNiInterface)
-       sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
+        sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
     if (sGpsNiInterface)
-       sGpsNiInterface->init(&sGpsNiCallbacks);
+        sGpsNiInterface->init(&sGpsNiCallbacks);
+
+    // Clear privacy lock while enabled
+    if (!sGpsPrivacyInterface)
+        sGpsPrivacyInterface = (const GpsPrivacyInterface*)sGpsInterface->get_extension(GPS_PRIVACY_INTERFACE);
+    if (sGpsPrivacyInterface)
+        sGpsPrivacyInterface->set_privacy_lock(0);
 
     if (!sGpsDebugInterface)
        sGpsDebugInterface = (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE);
@@ -235,6 +242,12 @@
 
 static void android_location_GpsLocationProvider_disable(JNIEnv* env, jobject obj)
 {
+    // Enable privacy lock while disabled
+    if (!sGpsPrivacyInterface)
+        sGpsPrivacyInterface = (const GpsPrivacyInterface*)sGpsInterface->get_extension(GPS_PRIVACY_INTERFACE);
+    if (sGpsPrivacyInterface)
+        sGpsPrivacyInterface->set_privacy_lock(1);
+
     pthread_mutex_lock(&sEventMutex);
     sPendingCallbacks |= kDisableRequest;
     pthread_cond_signal(&sEventCond);
@@ -476,12 +489,10 @@
 static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* env, jobject obj,
       jint notifId, jint response)
 {
-    if (!sGpsNiInterface) {
+    if (!sGpsNiInterface)
         sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
-    }
-    if (sGpsNiInterface) {
+    if (sGpsNiInterface)
         sGpsNiInterface->respond(notifId, response);
-    }
 }
 
 static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env, jobject obj)
@@ -523,9 +534,9 @@
     {"native_get_internal_state", "()Ljava/lang/String;", (void*)android_location_GpsLocationProvider_get_internal_state},
 };
 
-int register_android_location_GpsLocationProvider(JNIEnv* env)
+int register_android_server_location_GpsLocationProvider(JNIEnv* env)
 {
-    return jniRegisterNativeMethods(env, "com/android/internal/location/GpsLocationProvider", sMethods, NELEM(sMethods));
+    return jniRegisterNativeMethods(env, "com/android/server/location/GpsLocationProvider", sMethods, NELEM(sMethods));
 }
 
 } /* namespace android */
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index c16fdb8..d11e7e1 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -11,6 +11,7 @@
 int register_android_server_SensorService(JNIEnv* env);
 int register_android_server_VibratorService(JNIEnv* env);
 int register_android_server_SystemServer(JNIEnv* env);
+int register_android_server_location_GpsLocationProvider(JNIEnv* env);
 };
 
 using namespace android;
@@ -33,6 +34,7 @@
     register_android_server_SensorService(env);
     register_android_server_VibratorService(env);
     register_android_server_SystemServer(env);
+    register_android_server_location_GpsLocationProvider(env);
 
     return JNI_VERSION_1_4;
 }