Merge "Add support for emulating external storage on devices with no SD card"
diff --git a/Android.mk b/Android.mk
index 27f9e1e..30a67e3 100644
--- a/Android.mk
+++ b/Android.mk
@@ -163,6 +163,7 @@
 	core/java/com/android/internal/view/IInputMethodClient.aidl \
 	core/java/com/android/internal/view/IInputMethodManager.aidl \
 	core/java/com/android/internal/view/IInputMethodSession.aidl \
+	core/java/com/android/internal/widget/IRemoteViewsFactory.aidl \
 	location/java/android/location/IGeocodeProvider.aidl \
 	location/java/android/location/IGpsStatusListener.aidl \
 	location/java/android/location/IGpsStatusProvider.aidl \
diff --git a/api/current.xml b/api/current.xml
index b5435e4..76b1c9a 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -34218,6 +34218,40 @@
 <parameter name="context" type="android.content.Context">
 </parameter>
 </method>
+<method name="notifyAppWidgetViewDataChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="appWidgetIds" type="int[]">
+</parameter>
+<parameter name="views" type="android.widget.RemoteViews">
+</parameter>
+<parameter name="viewId" type="int">
+</parameter>
+</method>
+<method name="notifyAppWidgetViewDataChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="appWidgetId" type="int">
+</parameter>
+<parameter name="views" type="android.widget.RemoteViews">
+</parameter>
+<parameter name="viewId" type="int">
+</parameter>
+</method>
 <method name="updateAppWidget"
  return="void"
  abstract="false"
@@ -207092,6 +207126,28 @@
  visibility="public"
 >
 </method>
+<method name="onRemoteAdapterConnected"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onRemoteAdapterDisconnected"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="onRestoreInstanceState"
  return="void"
  abstract="false"
@@ -207269,6 +207325,19 @@
 <parameter name="listener" type="android.widget.AbsListView.RecyclerListener">
 </parameter>
 </method>
+<method name="setRemoteViewsAdapter"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
 <method name="setScrollIndicators"
  return="void"
  abstract="false"
@@ -213725,6 +213794,19 @@
 <parameter name="verticalSpacing" type="int">
 </parameter>
 </method>
+<method name="smoothScrollByOffset"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="offset" type="int">
+</parameter>
+</method>
 <field name="AUTO_FIT"
  type="int"
  transient="false"
@@ -216276,6 +216358,19 @@
 <parameter name="y" type="int">
 </parameter>
 </method>
+<method name="smoothScrollByOffset"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="offset" type="int">
+</parameter>
+</method>
 <field name="CHOICE_MODE_MULTIPLE"
  type="int"
  transient="false"
@@ -219130,6 +219225,23 @@
 <parameter name="value" type="int">
 </parameter>
 </method>
+<method name="setIntent"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="methodName" type="java.lang.String">
+</parameter>
+<parameter name="value" type="android.content.Intent">
+</parameter>
+</method>
 <method name="setLong"
  return="void"
  abstract="false"
@@ -219181,6 +219293,51 @@
 <parameter name="indeterminate" type="boolean">
 </parameter>
 </method>
+<method name="setRelativeScrollPosition"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="offset" type="int">
+</parameter>
+</method>
+<method name="setRemoteAdapter"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="setScrollPosition"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="position" type="int">
+</parameter>
+</method>
 <method name="setShort"
  return="void"
  abstract="false"
@@ -219343,6 +219500,149 @@
 <implements name="java.lang.annotation.Annotation">
 </implements>
 </class>
+<class name="RemoteViewsService"
+ extends="android.app.Service"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="RemoteViewsService"
+ type="android.widget.RemoteViewsService"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="onBind"
+ return="android.os.IBinder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onGetViewFactory"
+ return="android.widget.RemoteViewsService.RemoteViewsFactory"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+</class>
+<interface name="RemoteViewsService.RemoteViewsFactory"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getCount"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getItemId"
+ return="long"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="position" type="int">
+</parameter>
+</method>
+<method name="getLoadingView"
+ return="android.widget.RemoteViews"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getViewAt"
+ return="android.widget.RemoteViews"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="position" type="int">
+</parameter>
+</method>
+<method name="getViewTypeCount"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="hasStableIds"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onCreate"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onDestroy"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</interface>
 <class name="ResourceCursorAdapter"
  extends="android.widget.CursorAdapter"
  abstract="true"
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index b2fc13f..6011eec 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -39,6 +39,7 @@
 
     static final int HANDLE_UPDATE = 1;
     static final int HANDLE_PROVIDER_CHANGED = 2;
+    static final int HANDLE_VIEW_DATA_CHANGED = 3;
 
     final static Object sServiceLock = new Object();
     static IAppWidgetService sService;
@@ -60,6 +61,14 @@
             msg.obj = info;
             msg.sendToTarget();
         }
+
+        public void viewDataChanged(int appWidgetId, RemoteViews views, int viewId) {
+            Message msg = mHandler.obtainMessage(HANDLE_VIEW_DATA_CHANGED);
+            msg.arg1 = appWidgetId;
+            msg.arg2 = viewId;
+            msg.obj = views;
+            msg.sendToTarget();
+        }
     }
 
     class UpdateHandler extends Handler {
@@ -77,6 +86,10 @@
                     onProviderChanged(msg.arg1, (AppWidgetProviderInfo)msg.obj);
                     break;
                 }
+                case HANDLE_VIEW_DATA_CHANGED: {
+                    viewDataChanged(msg.arg1, (RemoteViews) msg.obj, msg.arg2);
+                    break;
+                }
             }
         }
     }
@@ -250,6 +263,16 @@
             v.updateAppWidget(views);
         }
     }
+
+    void viewDataChanged(int appWidgetId, RemoteViews views, int viewId) {
+        AppWidgetHostView v;
+        synchronized (mViews) {
+            v = mViews.get(appWidgetId);
+        }
+        if (v != null) {
+            v.viewDataChanged(views, viewId);
+        }
+    }
 }
 
 
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 3c19ea3..22f4266 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -32,6 +32,9 @@
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.widget.Adapter;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
 import android.widget.FrameLayout;
 import android.widget.RemoteViews;
 import android.widget.TextView;
@@ -258,6 +261,22 @@
     }
 
     /**
+     * Process data-changed notifications for the specified view in the specified
+     * set of {@link RemoteViews} views.
+     */
+    void viewDataChanged(RemoteViews remoteViews, int viewId) {
+        View v = findViewById(viewId);
+        if ((v != null) && (v instanceof AdapterView<?>)) {
+            AdapterView<?> adapterView = (AdapterView<?>) v;
+            Adapter adapter = adapterView.getAdapter();
+            if (adapter instanceof BaseAdapter) {
+                BaseAdapter baseAdapter = (BaseAdapter) adapter;
+                baseAdapter.notifyDataSetChanged();
+            }
+        }
+    }
+
+    /**
      * Build a {@link Context} cloned into another package name, usually for the
      * purposes of reading remote resources.
      */
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 3f12bf9..5ee721f 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -288,6 +288,35 @@
     }
 
     /**
+     * Notifies the specified collection view in all the specified AppWidget instances
+     * to invalidate their currently data.
+     *
+     * @param appWidgetIds  The AppWidget instances for which to notify of view data changes.
+     * @param views         The RemoteViews which contains the view referenced at viewId.
+     * @param viewId        The collection view id.
+     */
+    public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, RemoteViews views, int viewId) {
+        try {
+            sService.notifyAppWidgetViewDataChanged(appWidgetIds, views, viewId);
+        }
+        catch (RemoteException e) {
+            throw new RuntimeException("system server dead?", e);
+        }
+    }
+
+    /**
+     * Notifies the specified collection view in all the specified AppWidget instance
+     * to invalidate it's currently data.
+     *
+     * @param appWidgetId  The AppWidget instance for which to notify of view data changes.
+     * @param views         The RemoteViews which contains the view referenced at viewId.
+     * @param viewId        The collection view id.
+     */
+    public void notifyAppWidgetViewDataChanged(int appWidgetId, RemoteViews views, int viewId) {
+        notifyAppWidgetViewDataChanged(new int[] { appWidgetId }, views, viewId);
+    }
+
+    /**
      * Return a list of the AppWidget providers that are currently installed.
      */
     public List<AppWidgetProviderInfo> getInstalledProviders() {
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index 198c156..a6394e5 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -1017,6 +1017,15 @@
         }
 
         public static final Cursor query(ContentResolver cr, String[] projection,
+                                         long begin, long end, String searchQuery) {
+            Uri.Builder builder = CONTENT_SEARCH_URI.buildUpon();
+            ContentUris.appendId(builder, begin);
+            ContentUris.appendId(builder, end);
+            return cr.query(builder.build(), projection, WHERE_CALENDARS_SELECTED,
+                         new String[] { searchQuery }, DEFAULT_SORT_ORDER);
+        }
+
+        public static final Cursor query(ContentResolver cr, String[] projection,
                                          long begin, long end, String where, String orderBy) {
             Uri.Builder builder = CONTENT_URI.buildUpon();
             ContentUris.appendId(builder, begin);
@@ -1030,6 +1039,21 @@
                          null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
         }
 
+        public static final Cursor query(ContentResolver cr, String[] projection, long begin,
+                long end, String searchQuery, String where, String orderBy) {
+            Uri.Builder builder = CONTENT_SEARCH_URI.buildUpon();
+            ContentUris.appendId(builder, begin);
+            ContentUris.appendId(builder, end);
+            builder = builder.appendPath(searchQuery);
+            if (TextUtils.isEmpty(where)) {
+                where = WHERE_CALENDARS_SELECTED;
+            } else {
+                where = "(" + where + ") AND " + WHERE_CALENDARS_SELECTED;
+            }
+            return cr.query(builder.build(), projection, where, null,
+                    orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
+        }
+
         /**
          * The content:// style URL for this table
          */
@@ -1037,6 +1061,10 @@
                 "/instances/when");
         public static final Uri CONTENT_BY_DAY_URI =
             Uri.parse("content://" + AUTHORITY + "/instances/whenbyday");
+        public static final Uri CONTENT_SEARCH_URI = Uri.parse("content://" + AUTHORITY +
+                "/instances/search");
+        public static final Uri CONTENT_SEARCH_BY_DAY_URI =
+            Uri.parse("content://" + AUTHORITY + "/instances/searchbyday");
 
         /**
          * The default sort order for this table.
@@ -1053,7 +1081,6 @@
          * required for correctness, it just adds a nice touch.
          */
         public static final String SORT_CALENDAR_VIEW = "begin ASC, end DESC, title ASC";
-
         /**
          * The beginning time of the instance, in UTC milliseconds
          * <P>Type: INTEGER (long; millis since epoch)</P>
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 889d3b6..7df8487 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -675,7 +675,7 @@
         public static final String CONTACT_PRESENCE = "contact_presence";
 
         /**
-         * Contact Chat Capabilities. See {@link StatusColumns#CHAT_CAPABILITY} for individual
+         * Contact Chat Capabilities. See {@link StatusUpdates} for individual
          * definitions.
          * <p>Type: NUMBER</p>
          */
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 23219a3..8bee174 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -927,7 +927,7 @@
                 Log.e(TAG, "Error:Adapter Property at index" + i + "is null");
                 continue;
             }
-            if (name.equals("Devices")) {
+            if (name.equals("Devices") || name.equals("UUIDs")) {
                 StringBuilder str = new StringBuilder();
                 len = Integer.valueOf(properties[++i]);
                 for (int j = 0; j < len; j++) {
diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java
index bfa349c..2604cf9 100644
--- a/core/java/android/view/MenuItem.java
+++ b/core/java/android/view/MenuItem.java
@@ -401,6 +401,8 @@
      * Sets how this item should display in the presence of an Action Bar.
      *
      * @param actionEnum How the item should display. One of
+     * {@link #SHOW_AS_ACTION_ALWAYS}, {@link #SHOW_AS_ACTION_IF_ROOM}, or
+     * {@link #SHOW_AS_ACTION_NEVER}. SHOW_AS_ACTION_NEVER is the default.
      * 
      * @see android.app.ActionBar
      */
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 70c1e15..1658b2f 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -19,6 +19,7 @@
 import com.android.internal.R;
 
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Rect;
@@ -71,7 +72,8 @@
  */
 public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,
         ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener,
-        ViewTreeObserver.OnTouchModeChangeListener {
+        ViewTreeObserver.OnTouchModeChangeListener,
+        RemoteViewsAdapter.RemoteAdapterConnectionCallback {
 
     /**
      * Disables the transcript mode.
@@ -180,6 +182,11 @@
     ListAdapter mAdapter;
 
     /**
+     * The remote adapter containing the data to be displayed by this view to be set
+     */
+    private RemoteViewsAdapter mRemoteAdapter;
+
+    /**
      * Indicates whether the list selector should be drawn on top of the children or behind
      */
     boolean mDrawSelectorOnTop = false;
@@ -2893,6 +2900,42 @@
         mFlingRunnable.startScroll(distance, duration);
     }
 
+    /**
+     * Allows RemoteViews to scroll relatively to a position.
+     */
+    void smoothScrollByOffset(int position) {
+        int index = -1;
+        if (position < 0) {
+            index = getFirstVisiblePosition();
+        } else if (position > 0) {
+            index = getLastVisiblePosition();
+        }
+
+        if (index > -1) {
+            View child = getChildAt(index - getFirstVisiblePosition());
+            if (child != null) {
+                Rect visibleRect = new Rect();
+                if (child.getGlobalVisibleRect(visibleRect)) {
+                    // the child is partially visible
+                    int childRectArea = child.getWidth() * child.getHeight();
+                    int visibleRectArea = visibleRect.width() * visibleRect.height();
+                    float visibleArea = (visibleRectArea / (float) childRectArea);
+                    final float visibleThreshold = 0.75f;
+                    if ((position < 0) && (visibleArea < visibleThreshold)) {
+                        // the top index is not perceivably visible so offset
+                        // to account for showing that top index as well
+                        ++index;
+                    } else if ((position > 0) && (visibleArea < visibleThreshold)) {
+                        // the bottom index is not perceivably visible so offset
+                        // to account for showing that bottom index as well
+                        --index;
+                    }
+                }
+                smoothScrollToPosition(Math.max(0, Math.min(getCount(), index + position)));
+            }
+        }
+    }
+
     private void createScrollingCache() {
         if (mScrollingCacheEnabled && !mCachingStarted) {
             setChildrenDrawnWithCacheEnabled(true);
@@ -3905,6 +3948,34 @@
     }
 
     /**
+     * Sets up this AbsListView to use a remote views adapter which connects to a RemoteViewsService
+     * through the specified intent.
+     * @param intent the intent used to identify the RemoteViewsService for the adapter to connect to.
+     */
+    public void setRemoteViewsAdapter(Intent intent) {
+        mRemoteAdapter = new RemoteViewsAdapter(getContext(), intent, this);
+    }
+
+    /**
+     * Called back when the adapter connects to the RemoteViewsService.
+     */
+    public void onRemoteAdapterConnected() {
+        if (mRemoteAdapter != mAdapter) {
+            setAdapter(mRemoteAdapter);
+        }
+    }
+
+    /**
+     * Called back when the adapter disconnects from the RemoteViewsService.
+     */
+    public void onRemoteAdapterDisconnected() {
+        if (mRemoteAdapter == mAdapter) {
+            mRemoteAdapter = null;
+            setAdapter(null);
+        }
+    }
+
+    /**
      * Sets the recycler listener to be notified whenever a View is set aside in
      * the recycler for later reuse. This listener can be used to free resources
      * associated to the View.
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index fe69a13..a5b3ed5 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -17,22 +17,25 @@
 package android.widget;
 
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.TypedArray;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.KeyEvent;
+import android.view.SoundEffectConstants;
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
-import android.view.SoundEffectConstants;
 import android.view.animation.GridLayoutAnimationController;
+import android.widget.RemoteViews.RemoteView;
 
 
 /**
  * A view that shows items in two-dimensional scrolling grid. The items in the
  * grid come from the {@link ListAdapter} associated with this view.
  */
+@RemoteView
 public class GridView extends AbsListView {
     public static final int NO_STRETCH = 0;
     public static final int STRETCH_SPACING = 1;
@@ -107,6 +110,16 @@
     }
 
     /**
+     * Sets up this AbsListView to use a remote views adapter which connects to a RemoteViewsService
+     * through the specified intent.
+     * @param intent the intent used to identify the RemoteViewsService for the adapter to connect to.
+     */
+    @android.view.RemotableViewMethod
+    public void setRemoteViewsAdapter(Intent intent) {
+        super.setRemoteViewsAdapter(intent);
+    }
+
+    /**
      * Sets the data behind this GridView.
      *
      * @param adapter the adapter providing the grid's data
@@ -740,6 +753,26 @@
     }
 
     /**
+     * Smoothly scroll to the specified adapter position. The view will
+     * scroll such that the indicated position is displayed.
+     * @param position Scroll to this adapter position.
+     */
+    @android.view.RemotableViewMethod
+    public void smoothScrollToPosition(int position) {
+        super.smoothScrollToPosition(position);
+    }
+
+    /**
+     * Smoothly scroll to the specified adapter position offset. The view will
+     * scroll such that the indicated position is displayed.
+     * @param offset The amount to offset from the adapter position to scroll to.
+     */
+    @android.view.RemotableViewMethod
+    public void smoothScrollByOffset(int offset) {
+        super.smoothScrollByOffset(offset);
+    }
+
+    /**
      * Fills the grid based on positioning the new selection relative to the old
      * selection. The new selection will be placed at, above, or below the
      * location of the new selection depending on how the selection is moving.
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 86913ae..ad9d930 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -20,6 +20,7 @@
 import com.google.android.collect.Lists;
 
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Paint;
@@ -41,6 +42,7 @@
 import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.view.accessibility.AccessibilityEvent;
+import android.widget.RemoteViews.RemoteView;
 
 import java.util.ArrayList;
 
@@ -65,6 +67,7 @@
  * @attr ref android.R.styleable#ListView_headerDividersEnabled
  * @attr ref android.R.styleable#ListView_footerDividersEnabled
  */
+@RemoteView
 public class ListView extends AbsListView {
     /**
      * Used to indicate a no preference for a position type.
@@ -401,6 +404,16 @@
     }
 
     /**
+     * Sets up this AbsListView to use a remote views adapter which connects to a RemoteViewsService
+     * through the specified intent.
+     * @param intent the intent used to identify the RemoteViewsService for the adapter to connect to.
+     */
+    @android.view.RemotableViewMethod
+    public void setRemoteViewsAdapter(Intent intent) {
+        super.setRemoteViewsAdapter(intent);
+    }
+
+    /**
      * Sets the data behind this ListView.
      *
      * The adapter passed to this method may be wrapped by a {@link WrapperListAdapter},
@@ -863,6 +876,25 @@
         return topSelectionPixel;
     }
 
+    /**
+     * Smoothly scroll to the specified adapter position. The view will
+     * scroll such that the indicated position is displayed.
+     * @param position Scroll to this adapter position.
+     */
+    @android.view.RemotableViewMethod
+    public void smoothScrollToPosition(int position) {
+        super.smoothScrollToPosition(position);
+    }
+
+    /**
+     * Smoothly scroll to the specified adapter position offset. The view will
+     * scroll such that the indicated position is displayed.
+     * @param offset The amount to offset from the adapter position to scroll to.
+     */
+    @android.view.RemotableViewMethod
+    public void smoothScrollByOffset(int offset) {
+        super.smoothScrollByOffset(offset);
+    }
 
     /**
      * Fills the list based on positioning the new selection relative to the old
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index fc02acf..50745dc0 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -285,6 +285,7 @@
         static final int URI = 11;
         static final int BITMAP = 12;
         static final int BUNDLE = 13;
+        static final int INTENT = 14;
 
         int viewId;
         String methodName;
@@ -347,6 +348,9 @@
                 case BUNDLE:
                     this.value = in.readBundle();
                     break;
+                case INTENT:
+                    this.value = Intent.CREATOR.createFromParcel(in);
+                    break;
                 default:
                     break;
             }
@@ -402,6 +406,9 @@
                 case BUNDLE:
                     out.writeBundle((Bundle) this.value);
                     break;
+                case INTENT:
+                    ((Intent)this.value).writeToParcel(out, flags);
+                    break;
                 default:
                     break;
             }
@@ -435,6 +442,8 @@
                     return Bitmap.class;
                 case BUNDLE:
                     return Bundle.class;
+                case INTENT:
+                    return Intent.class;
                 default:
                     return null;
             }
@@ -770,6 +779,37 @@
     }
 
     /**
+     * Equivalent to calling {@link android.widget.AbsListView#setRemoteViewsAdapter(Intent)}.
+     *
+     * @param viewId The id of the view whose text should change
+     * @param intent The intent of the service which will be
+     *            providing data to the RemoteViewsAdapter
+     */
+    public void setRemoteAdapter(int viewId, Intent intent) {
+        setIntent(viewId, "setRemoteViewsAdapter", intent);
+    }
+
+    /**
+     * Equivalent to calling {@link android.widget.AbsListView#smoothScrollToPosition(int, int)}.
+     *
+     * @param viewId The id of the view whose text should change
+     * @param position Scroll to this adapter position
+     */
+    public void setScrollPosition(int viewId, int position) {
+        setInt(viewId, "smoothScrollToPosition", position);
+    }
+
+    /**
+     * Equivalent to calling {@link android.widget.AbsListView#smoothScrollToPosition(int, int)}.
+     *
+     * @param viewId The id of the view whose text should change
+     * @param offset Scroll by this adapter position offset
+     */
+    public void setRelativeScrollPosition(int viewId, int offset) {
+        setInt(viewId, "smoothScrollByOffset", offset);
+    }
+
+    /**
      * Call a method taking one boolean on a view in the layout for this RemoteViews.
      *
      * @param viewId The id of the view whose text should change
@@ -916,6 +956,16 @@
     }
 
     /**
+     *
+     * @param viewId
+     * @param methodName
+     * @param value
+     */
+    public void setIntent(int viewId, String methodName, Intent value) {
+        addAction(new ReflectionAction(viewId, methodName, ReflectionAction.INTENT, value));
+    }
+
+    /**
      * Inflates the view hierarchy represented by this object and applies
      * all of the actions.
      * 
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
new file mode 100644
index 0000000..d426033
--- /dev/null
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -0,0 +1,666 @@
+/*
+ * 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 android.widget;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.graphics.Color;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.MeasureSpec;
+
+import com.android.internal.widget.IRemoteViewsFactory;
+
+/**
+ * An adapter to a RemoteViewsService which fetches and caches RemoteViews
+ * to be later inflated as child views.
+ */
+/** @hide */
+public class RemoteViewsAdapter extends BaseAdapter {
+
+    private static final String LOG_TAG = "RemoteViewsAdapter";
+
+    private Context mContext;
+    private Intent mIntent;
+    private RemoteViewsAdapterServiceConnection mServiceConnection;
+    private RemoteViewsCache mViewCache;
+
+    private HandlerThread mWorkerThread;
+    // items may be interrupted within the normally processed queues
+    private Handler mWorkerQueue;
+    private Handler mMainQueue;
+    // items are never dequeued from the priority queue and must run
+    private Handler mWorkerPriorityQueue;
+    private Handler mMainPriorityQueue;
+
+    /**
+     * An interface for the RemoteAdapter to notify other classes when adapters
+     * are actually connected to/disconnected from their actual services.
+     */
+    public interface RemoteAdapterConnectionCallback {
+        public void onRemoteAdapterConnected();
+
+        public void onRemoteAdapterDisconnected();
+    }
+
+    /**
+     * The service connection that gets populated when the RemoteViewsService is
+     * bound.
+     */
+    private class RemoteViewsAdapterServiceConnection implements ServiceConnection {
+        private boolean mConnected;
+        private IRemoteViewsFactory mRemoteViewsFactory;
+        private RemoteAdapterConnectionCallback mCallback;
+
+        public RemoteViewsAdapterServiceConnection(RemoteAdapterConnectionCallback callback) {
+            mCallback = callback;
+        }
+
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            mRemoteViewsFactory = IRemoteViewsFactory.Stub.asInterface(service);
+            mConnected = true;
+            // notifyDataSetChanged should be called first, to ensure that the
+            // views are not updated twice
+            notifyDataSetChanged();
+
+            // post a new runnable to load the appropriate data, then callback
+            mWorkerPriorityQueue.post(new Runnable() {
+                @Override
+                public void run() {
+                    // we need to get the viewTypeCount specifically, so just get all the
+                    // metadata
+                    mViewCache.requestMetaData();
+
+                    // post a runnable to call the callback on the main thread
+                    mMainPriorityQueue.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            if (mCallback != null)
+                                mCallback.onRemoteAdapterConnected();
+                        }
+                    });
+                }
+            });
+        }
+
+        public void onServiceDisconnected(ComponentName name) {
+            mRemoteViewsFactory = null;
+            mConnected = false;
+            if (mCallback != null)
+                mCallback.onRemoteAdapterDisconnected();
+
+            // clear the main/worker queues
+            mMainQueue.removeMessages(0);
+            mWorkerQueue.removeMessages(0);
+        }
+
+        public IRemoteViewsFactory getRemoteViewsFactory() {
+            return mRemoteViewsFactory;
+        }
+
+        public boolean isConnected() {
+            return mConnected;
+        }
+    }
+
+    /**
+     * An internal cache of remote views.
+     */
+    private class RemoteViewsCache {
+        private RemoteViewsInfo mViewCacheInfo;
+        private RemoteViewsIndexInfo[] mViewCache;
+
+        // if a user loading view is not provided, then we create a temporary one
+        // for the user using the height of the first view
+        private RemoteViews mUserLoadingView;
+        private RemoteViews mFirstView;
+        private int mFirstViewHeight;
+
+        // determines when the current cache window needs to be updated with new
+        // items (ie. when there is not enough slack)
+        private int mViewCacheStartPosition;
+        private int mViewCacheEndPosition;
+        private int mHalfCacheSize;
+        private int mCacheSlack;
+        private final float mCacheSlackPercentage = 0.75f;
+
+        // determines whether to reorder the posted items on the worker thread
+        // so that the items in the current window can be loaded first
+        private int mPriorityLoadingWindowSize;
+        private int mPriorityLoadingWindowStart;
+        private int mPriorityLoadingWindowEnd;
+
+        // determines which way to load items in the current window based on how
+        // the window shifted last
+        private boolean mLoadUpwards;
+
+        /**
+         * The data structure stored at each index of the cache. Any member 
+         * that is not invalidated persists throughout the lifetime of the cache.
+         */
+        private class RemoteViewsIndexInfo {
+            FrameLayout flipper;
+            RemoteViews view;
+            long itemId;
+            int typeId;
+
+            RemoteViewsIndexInfo() {
+                invalidate();
+            }
+
+            void set(RemoteViews v, long id) {
+                view = v;
+                itemId = id;
+                if (v != null)
+                    typeId = v.getLayoutId();
+                else
+                    typeId = 0;
+            }
+
+            void invalidate() {
+                view = null;
+                itemId = 0;
+                typeId = 0;
+            }
+
+            final boolean isValid() {
+                return (view != null);
+            }
+        }
+
+        /**
+         * Remote adapter metadata. Useful for when we have to lock on something
+         * before updating the metadata.
+         */
+        private class RemoteViewsInfo {
+            int count;
+            int viewTypeCount;
+            boolean hasStableIds;
+            Map<Integer, Integer> mTypeIdIndexMap;
+
+            RemoteViewsInfo() {
+                count = 0;
+                // by default there is at least one dummy view type
+                viewTypeCount = 1;
+                hasStableIds = true;
+                mTypeIdIndexMap = new HashMap<Integer, Integer>();
+            }
+        }
+
+        public RemoteViewsCache(int halfCacheSize) {
+            mHalfCacheSize = halfCacheSize;
+            mCacheSlack = Math.round(mCacheSlackPercentage * mHalfCacheSize);
+            mViewCacheStartPosition = 0;
+            mViewCacheEndPosition = -1;
+            mPriorityLoadingWindowSize = 4;
+            mPriorityLoadingWindowStart = 0;
+            mPriorityLoadingWindowEnd = 0;
+            mLoadUpwards = false;
+
+            // initialize the cache
+            mViewCacheInfo = new RemoteViewsInfo();
+            mViewCache = new RemoteViewsIndexInfo[2 * mHalfCacheSize + 1];
+            for (int i = 0; i < mViewCache.length; ++i) {
+                mViewCache[i] = new RemoteViewsIndexInfo();
+            }
+        }
+
+        private final boolean contains(int position) {
+            // take the modulo of the position
+            return (mViewCacheStartPosition <= position) && (position < mViewCacheEndPosition);
+        }
+
+        private final boolean containsAndIsValid(int position) {
+            if (contains(position)) {
+                RemoteViewsIndexInfo indexInfo = mViewCache[getCacheIndex(position)];
+                if (indexInfo.isValid()) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private final int getCacheIndex(int position) {
+            return (mViewCache.length + (position % mViewCache.length)) % mViewCache.length;
+        }
+
+        public void requestMetaData() {
+            if (mServiceConnection.isConnected()) {
+                try {
+                    IRemoteViewsFactory factory = mServiceConnection.getRemoteViewsFactory();
+
+                    // get the properties/first view (so that we can use it to
+                    // measure our dummy views)
+                    boolean hasStableIds = factory.hasStableIds();
+                    int viewTypeCount = factory.getViewTypeCount();
+                    int count = factory.getCount();
+                    RemoteViews loadingView = factory.getLoadingView();
+                    RemoteViews firstView = null;
+                    if ((count > 0) && (loadingView == null)) {
+                        firstView = factory.getViewAt(0);
+                    }
+                    synchronized (mViewCacheInfo) {
+                        RemoteViewsInfo info = mViewCacheInfo;
+                        info.hasStableIds = hasStableIds;
+                        info.viewTypeCount = viewTypeCount + 1;
+                        info.count = count;
+                        mUserLoadingView = loadingView;
+                        if (firstView != null) {
+                            mFirstView = firstView;
+                            mFirstViewHeight = -1;
+                        }
+                    }
+                } catch (RemoteException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+
+        protected void updateRemoteViewsInfo(int position) {
+            if (mServiceConnection.isConnected()) {
+                IRemoteViewsFactory factory = mServiceConnection.getRemoteViewsFactory();
+
+                // load the item information
+                RemoteViews remoteView = null;
+                long itemId = 0;
+                try {
+                    remoteView = factory.getViewAt(position);
+                    itemId = factory.getItemId(position);
+                } catch (RemoteException e) {
+                    e.printStackTrace();
+                }
+
+                synchronized (mViewCache) {
+                    // skip if the window has moved
+                    if (position < mViewCacheStartPosition || position >= mViewCacheEndPosition)
+                        return;
+
+                    final int positionIndex = position;
+                    final int cacheIndex = getCacheIndex(position);
+                    mViewCache[cacheIndex].set(remoteView, itemId);
+
+                    // notify the main thread when done loading
+                    // flush pending updates
+                    mMainQueue.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            // swap the loader view for this view
+                            synchronized (mViewCache) {
+                                if (containsAndIsValid(positionIndex)) {
+                                    RemoteViewsIndexInfo indexInfo = mViewCache[cacheIndex];
+                                    FrameLayout flipper = indexInfo.flipper;
+
+                                    // recompose the flipper
+                                    View loadingView = flipper.getChildAt(0);
+                                    loadingView.setVisibility(View.GONE);
+                                    flipper.removeAllViews();
+                                    flipper.addView(loadingView);
+                                    flipper.addView(indexInfo.view.apply(mContext, flipper));
+
+                                    // hide the loader view and bring the new view to the front
+                                    flipper.requestLayout();
+                                    flipper.invalidate();
+                                }
+                            }
+                        }
+                    });
+                }
+            }
+        }
+
+        private RemoteViewsIndexInfo requestCachedIndexInfo(final int position) {
+            int indicesToLoadCount = 0;
+            int[] indicesToLoad = null;
+
+            synchronized (mViewCache) {
+                indicesToLoad = new int[mViewCache.length];
+                Arrays.fill(indicesToLoad, 0);
+
+                if (containsAndIsValid(position)) {
+                    // return the info if it exists in the window and is loaded
+                    return mViewCache[getCacheIndex(position)];
+                } 
+
+                // if necessary update the window and load the new information
+                int centerPosition = (mViewCacheEndPosition + mViewCacheStartPosition) / 2;
+                if ((mViewCacheEndPosition <= mViewCacheStartPosition) || (Math.abs(position - centerPosition) > mCacheSlack)) {
+                    int newStartPosition = position - mHalfCacheSize;
+                    int newEndPosition = position + mHalfCacheSize;
+
+                    // prune/add before the current start position
+                    int effectiveStart = Math.max(newStartPosition, 0);
+                    int effectiveEnd = Math.min(newEndPosition, getCount());
+
+                    mWorkerQueue.removeMessages(0);
+
+                    // invalidate items in the queue
+                    boolean loadFromBeginning = effectiveStart < mViewCacheStartPosition;
+                    int numLoadFromBeginning = mViewCacheStartPosition - effectiveStart;
+                    boolean loadFromEnd = effectiveEnd > mViewCacheEndPosition;
+                    int overlapStart = Math.max(mViewCacheStartPosition, effectiveStart);
+                    int overlapEnd = Math.min(Math.max(mViewCacheStartPosition, mViewCacheEndPosition), effectiveEnd);
+                    for (int i = newStartPosition; i < newEndPosition; ++i) {
+                        if (loadFromBeginning && (effectiveStart <= i) && (i < overlapStart)) {
+                            // load new items at the beginning in reverse order
+                            mViewCache[getCacheIndex(i)].invalidate();
+                            indicesToLoad[indicesToLoadCount++] = effectiveStart
+                                    + (numLoadFromBeginning - (i - effectiveStart) - 1);
+                        } else if (loadFromEnd && (overlapEnd <= i) && (i < effectiveEnd)) {
+                            mViewCache[getCacheIndex(i)].invalidate();
+                            indicesToLoad[indicesToLoadCount++] = i;
+                        } else if ((overlapStart <= i) && (i < overlapEnd)) {
+                            // load the stuff in the middle that has not already
+                            // been loaded
+                            if (!mViewCache[getCacheIndex(i)].isValid()) {
+                                indicesToLoad[indicesToLoadCount++] = i;
+                            }
+                        } else {
+                            // invalidate all other cache indices (outside the effective start/end)
+                            mViewCache[getCacheIndex(i)].invalidate();
+                        }
+                    }
+
+                    mViewCacheStartPosition = newStartPosition;
+                    mViewCacheEndPosition = newEndPosition;
+                    mPriorityLoadingWindowStart = position;
+                    mPriorityLoadingWindowEnd = position + mPriorityLoadingWindowSize;
+                    mLoadUpwards = loadFromBeginning && !loadFromEnd;
+                } else if (contains(position)) {
+                    // prioritize items around this position so that they load first
+                    if (position < mPriorityLoadingWindowStart || position > mPriorityLoadingWindowEnd) {
+                        mWorkerQueue.removeMessages(0);
+
+                        int index;
+                        int effectiveStart = Math.max(position - mPriorityLoadingWindowSize, 0);
+                        int effectiveEnd = 0;
+                        synchronized (mViewCacheInfo) {
+                            effectiveEnd = Math.min(position + mPriorityLoadingWindowSize - 1,
+                                    mViewCacheInfo.count - 1);
+                        }
+
+                        for (int i = 0; i < mViewCache.length; ++i) {
+                            if (mLoadUpwards) {
+                                index = effectiveEnd - i;
+                            } else {
+                                index = effectiveStart + i;
+                            }
+                            if (!mViewCache[getCacheIndex(index)].isValid()) {
+                                indicesToLoad[indicesToLoadCount++] = index;
+                            }
+                        }
+
+                        mPriorityLoadingWindowStart = effectiveStart;
+                        mPriorityLoadingWindowEnd = position + mPriorityLoadingWindowSize;
+                    }
+                }
+            }
+
+            // post items to be loaded
+            int length = 0;
+            synchronized (mViewCacheInfo) {
+                length = mViewCacheInfo.count;
+            }
+            for (int i = 0; i < indicesToLoadCount; ++i) {
+                final int index = indicesToLoad[i];
+                if (0 <= index && index < length) {
+                    mWorkerQueue.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            updateRemoteViewsInfo(index);
+                        }
+                    });
+                }
+            }
+
+            // return null so that a dummy view can be retrieved
+            return null;
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (mServiceConnection.isConnected()) {
+                // create the flipper views if necessary (we have to do this now
+                // for all the flippers while we have the reference to the parent)
+                createInitialLoadingFlipperViews(parent);
+
+                // request the item from the cache (queueing it to load if not
+                // in the cache already)
+                RemoteViewsIndexInfo indexInfo = requestCachedIndexInfo(position);
+
+                // update the flipper appropriately
+                synchronized (mViewCache) {
+                    int cacheIndex = getCacheIndex(position);
+                    FrameLayout flipper = mViewCache[cacheIndex].flipper;
+
+                    if (indexInfo == null) {
+                        // hide the item view and show the loading view
+                        flipper.getChildAt(0).setVisibility(View.VISIBLE);
+                        for (int i = 1; i < flipper.getChildCount(); ++i) {
+                            flipper.getChildAt(i).setVisibility(View.GONE);
+                        }
+                        flipper.requestLayout();
+                        flipper.invalidate();
+                    } else {
+                        // hide the loading view and show the item view
+                        for (int i = 0; i < flipper.getChildCount() - 1; ++i) {
+                            flipper.getChildAt(i).setVisibility(View.GONE);
+                        }
+                        flipper.getChildAt(flipper.getChildCount() - 1).setVisibility(View.VISIBLE);
+                        flipper.requestLayout();
+                        flipper.invalidate();
+                    }
+                    return flipper;
+                }
+            }
+            return new View(mContext);
+        }
+
+        private void createInitialLoadingFlipperViews(ViewGroup parent) {
+            // ensure that the cache has the appropriate initial flipper
+            synchronized (mViewCache) {
+                if (mViewCache[0].flipper == null) {
+                    for (int i = 0; i < mViewCache.length; ++i) {
+                        FrameLayout flipper = new FrameLayout(mContext);
+                        if (mUserLoadingView != null) {
+                            // use the user-specified loading view
+                            flipper.addView(mUserLoadingView.apply(mContext, parent));
+                        } else {
+                            // calculate the original size of the first row for the loader view
+                            synchronized (mViewCacheInfo) {
+                                if (mFirstViewHeight < 0) {
+                                    View firstView = mFirstView.apply(mContext, parent);
+                                    firstView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
+                                            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+                                    mFirstViewHeight = firstView.getMeasuredHeight();
+                                }
+                            }
+
+                            // construct a new loader and add it to the flipper as the fallback
+                            // default view
+                            TextView textView = new TextView(mContext);
+                            textView.setText("Loading...");
+                            textView.setHeight(mFirstViewHeight);
+                            textView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
+                            textView.setTextSize(18.0f);
+                            textView.setTextColor(Color.argb(96, 255, 255, 255));
+                            textView.setShadowLayer(2.0f, 0.0f, 1.0f, Color.BLACK);
+
+                            flipper.addView(textView);
+                        }
+                        mViewCache[i].flipper = flipper;
+                    }
+                }
+            }
+        }
+
+        public long getItemId(int position) {
+            synchronized (mViewCache) {
+                if (containsAndIsValid(position)) {
+                    return mViewCache[getCacheIndex(position)].itemId;
+                }
+            }
+            return 0;
+        }
+
+        public int getItemViewType(int position) {
+            // synchronize to ensure that the type id/index map is updated synchronously
+            synchronized (mViewCache) {
+                if (containsAndIsValid(position)) {
+                    int viewId = mViewCache[getCacheIndex(position)].typeId;
+                    Map<Integer, Integer> typeMap = mViewCacheInfo.mTypeIdIndexMap;
+                    // we +1 because the default dummy view get view type 0
+                    if (typeMap.containsKey(viewId)) {
+                        return typeMap.get(viewId);
+                    } else {
+                        int newIndex = typeMap.size() + 1;
+                        typeMap.put(viewId, newIndex);
+                        return newIndex;
+                    }
+                }
+            }
+            // return the type of the default item
+            return 0;
+        }
+
+        public int getCount() {
+            synchronized (mViewCacheInfo) {
+                return mViewCacheInfo.count;
+            }
+        }
+
+        public int getViewTypeCount() {
+            synchronized (mViewCacheInfo) {
+                return mViewCacheInfo.viewTypeCount;
+            }
+        }
+
+        public boolean hasStableIds() {
+            synchronized (mViewCacheInfo) {
+                return mViewCacheInfo.hasStableIds;
+            }
+        }
+
+        public void flushCache() {
+            synchronized (mViewCache) {
+                // flush the internal cache and invalidate the adapter for future loads
+                mWorkerQueue.removeMessages(0);
+                mMainQueue.removeMessages(0);
+
+                for (int i = 0; i < mViewCache.length; ++i) {
+                    mViewCache[i].invalidate();
+                }
+
+                mViewCacheStartPosition = 0;
+                mViewCacheEndPosition = -1;
+            }
+        }
+    }
+
+    public RemoteViewsAdapter(Context context, Intent intent, RemoteAdapterConnectionCallback callback) {
+        mContext = context;
+        mIntent = intent;
+
+        // initialize the worker thread
+        mWorkerThread = new HandlerThread("RemoteViewsCache-loader");
+        mWorkerThread.start();
+        mWorkerQueue = new Handler(mWorkerThread.getLooper());
+        mWorkerPriorityQueue = new Handler(mWorkerThread.getLooper());
+        mMainQueue = new Handler(Looper.myLooper());
+        mMainPriorityQueue = new Handler(Looper.myLooper());
+
+        // initialize the cache and the service connection on startup
+        mViewCache = new RemoteViewsCache(25);
+        mServiceConnection = new RemoteViewsAdapterServiceConnection(callback);
+        requestBindService();
+    }
+
+    protected void finalize() throws Throwable {
+        // remember to unbind from the service when finalizing
+        unbindService();
+    }
+
+    public int getCount() {
+        requestBindService();
+        return mViewCache.getCount();
+    }
+
+    public Object getItem(int position) {
+        // disallow arbitrary object to be associated with an item for the time being
+        return null;
+    }
+
+    public long getItemId(int position) {
+        requestBindService();
+        return mViewCache.getItemId(position);
+    }
+
+    public int getItemViewType(int position) {
+        requestBindService();
+        return mViewCache.getItemViewType(position);
+    }
+
+    public View getView(int position, View convertView, ViewGroup parent) {
+        requestBindService();
+        return mViewCache.getView(position, convertView, parent);
+    }
+
+    public int getViewTypeCount() {
+        requestBindService();
+        return mViewCache.getViewTypeCount();
+    }
+
+    public boolean hasStableIds() {
+        requestBindService();
+        return mViewCache.hasStableIds();
+    }
+
+    public boolean isEmpty() {
+        return getCount() <= 0;
+    }
+
+    public void notifyDataSetChanged() {
+        // flush the cache so that we can reload new items from the service
+        mViewCache.flushCache();
+        super.notifyDataSetChanged();
+    }
+
+    private boolean requestBindService() {
+        // try binding the service (which will start it if it's not already running)
+        if (!mServiceConnection.isConnected()) {
+            mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
+        }
+
+        return mServiceConnection.isConnected();
+    }
+
+    private void unbindService() {
+        if (mServiceConnection.isConnected()) {
+            mContext.unbindService(mServiceConnection);
+        }
+    }
+}
diff --git a/core/java/android/widget/RemoteViewsService.java b/core/java/android/widget/RemoteViewsService.java
new file mode 100644
index 0000000..7c9d7ff
--- /dev/null
+++ b/core/java/android/widget/RemoteViewsService.java
@@ -0,0 +1,140 @@
+/*
+ * 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 android.widget;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.util.Pair;
+
+import com.android.internal.widget.IRemoteViewsFactory;
+
+/**
+ * The service to be connected to for a remote adapter to request RemoteViews.  Users should
+ * extend the RemoteViewsService to provide the appropriate RemoteViewsFactory's used to
+ * populate the remote collection view (ListView, GridView, etc).
+ */
+public abstract class RemoteViewsService extends Service {
+
+    private static final String LOG_TAG = "RemoteViewsService";
+
+    // multimap implementation for reference counting
+    private HashMap<Intent, Pair<RemoteViewsFactory, Integer>> mRemoteViewFactories;
+    private final Object mLock = new Object();
+
+    /**
+     * An interface for an adapter between a remote collection view (ListView, GridView, etc) and
+     * the underlying data for that view.  The implementor is responsible for making a RemoteView
+     * for each item in the data set.
+     */
+    public interface RemoteViewsFactory {
+        public void onCreate();
+        public void onDestroy();
+
+        public int getCount();
+        public RemoteViews getViewAt(int position);
+        public RemoteViews getLoadingView();
+        public int getViewTypeCount();
+        public long getItemId(int position);
+        public boolean hasStableIds();
+    }
+
+    /**
+     * A private proxy class for the private IRemoteViewsFactory interface through the
+     * public RemoteViewsFactory interface.
+     */
+    private class RemoteViewsFactoryAdapter extends IRemoteViewsFactory.Stub {
+        public RemoteViewsFactoryAdapter(RemoteViewsFactory factory) {
+            mFactory = factory;
+        }
+
+        public int getCount() {
+            return mFactory.getCount();
+        }
+        public RemoteViews getViewAt(int position) {
+            return mFactory.getViewAt(position);
+        }
+        public RemoteViews getLoadingView() {
+            return mFactory.getLoadingView();
+        }
+        public int getViewTypeCount() {
+            return mFactory.getViewTypeCount();
+        }
+        public long getItemId(int position) {
+            return mFactory.getItemId(position);
+        }
+        public boolean hasStableIds() {
+            return mFactory.hasStableIds();
+        }
+
+        private RemoteViewsFactory mFactory;
+    }
+
+    public RemoteViewsService() {
+        mRemoteViewFactories = new HashMap<Intent, Pair<RemoteViewsFactory, Integer>>();
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        synchronized (mLock) {
+            // increment the reference count to the particular factory associated with this intent
+            Pair<RemoteViewsFactory, Integer> factoryRef = null;
+            RemoteViewsFactory factory = null;
+            if (!mRemoteViewFactories.containsKey(intent)) {
+                factory = onGetViewFactory(intent);
+                factoryRef = new Pair<RemoteViewsFactory, Integer>(factory, 1);
+                mRemoteViewFactories.put(intent, factoryRef);
+                factory.onCreate();
+            } else {
+                Pair<RemoteViewsFactory, Integer> oldFactoryRef = mRemoteViewFactories.get(intent);
+                factory = oldFactoryRef.first;
+                int newRefCount = oldFactoryRef.second.intValue() + 1;
+                factoryRef = new Pair<RemoteViewsFactory, Integer>(oldFactoryRef.first, newRefCount);
+                mRemoteViewFactories.put(intent, factoryRef);
+            }
+            return new RemoteViewsFactoryAdapter(factory);
+        }
+    }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        synchronized (mLock) {
+            if (mRemoteViewFactories.containsKey(intent)) {
+                // this alleviates the user's responsibility of having to clear all factories
+                Pair<RemoteViewsFactory, Integer> oldFactoryRef = mRemoteViewFactories.get(intent);
+                int newRefCount = oldFactoryRef.second.intValue() - 1;
+                if (newRefCount <= 0) {
+                    oldFactoryRef.first.onDestroy();
+                    mRemoteViewFactories.remove(intent);
+                } else {
+                    Pair<RemoteViewsFactory, Integer> factoryRef = new Pair<RemoteViewsFactory, Integer>(oldFactoryRef.first, newRefCount);
+                    mRemoteViewFactories.put(intent, factoryRef);
+                }
+            }
+        }
+        return super.onUnbind(intent);
+    }
+
+    /**
+     * To be implemented by the derived service to generate appropriate factories for
+     * the data.
+     */
+    public abstract RemoteViewsFactory onGetViewFactory(Intent intent);
+}
diff --git a/core/java/com/android/internal/appwidget/IAppWidgetHost.aidl b/core/java/com/android/internal/appwidget/IAppWidgetHost.aidl
index 2ed4773..f0920d1 100644
--- a/core/java/com/android/internal/appwidget/IAppWidgetHost.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetHost.aidl
@@ -24,5 +24,6 @@
 oneway interface IAppWidgetHost {
     void updateAppWidget(int appWidgetId, in RemoteViews views);
     void providerChanged(int appWidgetId, in AppWidgetProviderInfo info);
+    void viewDataChanged(int appWidgetId, in RemoteViews views, int viewId);
 }
 
diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
index 496aa1a..af75d5b 100644
--- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
@@ -41,6 +41,7 @@
     //
     void updateAppWidgetIds(in int[] appWidgetIds, in RemoteViews views);
     void updateAppWidgetProvider(in ComponentName provider, in RemoteViews views);
+    void notifyAppWidgetViewDataChanged(in int[] appWidgetIds, in RemoteViews views, int viewId);
     List<AppWidgetProviderInfo> getInstalledProviders();
     AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId);
     void bindAppWidgetId(int appWidgetId, in ComponentName provider);
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index b57b7a8..cd9832f 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -75,8 +75,9 @@
         mCloseDrawable = a.getDrawable(
                 com.android.internal.R.styleable.Theme_actionBarCloseContextDrawable);
         mItemMargin = mItemPadding / 2;
-        
-        mContentHeight = CONTENT_HEIGHT_DIP;
+
+        mContentHeight =
+                (int) (CONTENT_HEIGHT_DIP * getResources().getDisplayMetrics().density + 0.5f);
         a.recycle();
     }
     
diff --git a/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
new file mode 100644
index 0000000..7851347
--- /dev/null
+++ b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.widget.RemoteViews;
+
+/** {@hide} */
+interface IRemoteViewsFactory {
+    int getCount();
+    RemoteViews getViewAt(int position);
+    RemoteViews getLoadingView();
+    int getViewTypeCount();
+    long getItemId(int position);
+    boolean hasStableIds();
+}
+
diff --git a/docs/html/guide/developing/eclipse-adt.jd b/docs/html/guide/developing/eclipse-adt.jd
index 66379a3..9c77ece 100644
--- a/docs/html/guide/developing/eclipse-adt.jd
+++ b/docs/html/guide/developing/eclipse-adt.jd
@@ -785,6 +785,8 @@
 have first started <a href="{@docRoot}guide/developing/tools/ddms.html">DDMS</a>). </p>
 
 
+
+
 <!-- TODO: clean this up and expand it to cover more wizards and features
 <h3>ADT Wizards</h3>
 
diff --git a/libs/rs/java/ImageProcessing/res/raw/horizontal_blur.rs b/libs/rs/java/ImageProcessing/res/raw/horizontal_blur.rs
index 7b0e6bc..10815fb 100644
--- a/libs/rs/java/ImageProcessing/res/raw/horizontal_blur.rs
+++ b/libs/rs/java/ImageProcessing/res/raw/horizontal_blur.rs
@@ -5,17 +5,14 @@
 
 #include "ip.rsh"
 
-uchar4 * ScratchPixel;
-
-#pragma rs export_var(ScratchPixel)
-
 void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
     uchar4 *output = (uchar4 *)v_out;
-    const uchar4 *input = (uchar4 *)v_in;
     const FilterStruct *fs = (const FilterStruct *)usrData;
+    const uchar4 *input = (const uchar4 *)rsGetElementAt(fs->ain, 0, y);
 
     float4 blurredPixel = 0;
     float4 currentPixel = 0;
+
     for(int r = -fs->radius; r <= fs->radius; r ++) {
         // Stepping left and right away from the pixel
         int validW = x + r;
diff --git a/libs/rs/java/ImageProcessing/res/raw/horizontal_blur_bc.bc b/libs/rs/java/ImageProcessing/res/raw/horizontal_blur_bc.bc
index c9ba5d9..5920f3a 100644
--- a/libs/rs/java/ImageProcessing/res/raw/horizontal_blur_bc.bc
+++ b/libs/rs/java/ImageProcessing/res/raw/horizontal_blur_bc.bc
Binary files differ
diff --git a/libs/rs/java/ImageProcessing/res/raw/ip.rsh b/libs/rs/java/ImageProcessing/res/raw/ip.rsh
index 4073304..dea92c3 100644
--- a/libs/rs/java/ImageProcessing/res/raw/ip.rsh
+++ b/libs/rs/java/ImageProcessing/res/raw/ip.rsh
@@ -3,6 +3,8 @@
 #define MAX_RADIUS 25
 
 typedef struct {
+    rs_allocation ain;
+
     float *gaussian; //[MAX_RADIUS * 2 + 1];
     rs_matrix3x3 colorMat;
 
diff --git a/libs/rs/java/ImageProcessing/res/raw/threshold.rs b/libs/rs/java/ImageProcessing/res/raw/threshold.rs
index ecbfac4..aa6b6fa 100644
--- a/libs/rs/java/ImageProcessing/res/raw/threshold.rs
+++ b/libs/rs/java/ImageProcessing/res/raw/threshold.rs
@@ -24,7 +24,6 @@
 static float inWMinInB;
 static float outWMinOutB;
 static float overInWMinInB;
-static FilterStruct filterStruct;
 
 #pragma rs export_var(height, width, radius, InPixel, OutPixel, ScratchPixel, inBlack, outBlack, inWhite, outWhite, gamma, saturation, InPixel, OutPixel, ScratchPixel, vBlurScript, hBlurScript)
 #pragma rs export_func(filter, filterBenchmark);
@@ -106,138 +105,70 @@
     }
 }
 
-// This needs to be inline
-static float4 levelsSaturation(float4 currentPixel) {
-    float3 temp = rsMatrixMultiply(&colorMat, currentPixel.xyz);
-    temp = (clamp(temp, 0.1f, 255.f) - inBlack) * overInWMinInB;
-    temp = pow(temp, (float3)gamma);
-    currentPixel.xyz = clamp(temp * outWMinOutB + outBlack, 0.1f, 255.f);
-    return currentPixel;
-}
-
 static void processNoBlur() {
-    int w, h, r;
-    int count = 0;
-
     float inWMinInB = inWhite - inBlack;
     float outWMinOutB = outWhite - outBlack;
     float4 currentPixel = 0;
 
-    for(h = 0; h < height; h ++) {
-        for(w = 0; w < width; w ++) {
-            uchar4 *input = InPixel + h*width + w;
+    for(int h = 0; h < height; h ++) {
+        uchar4 *input = InPixel + h*width;
+        uchar4 *output = OutPixel + h*width;
 
+        for(int w = 0; w < width; w ++) {
             //currentPixel.xyz = convert_float3(input.xyz);
             currentPixel.x = (float)(input->x);
             currentPixel.y = (float)(input->y);
             currentPixel.z = (float)(input->z);
 
-            currentPixel = levelsSaturation(currentPixel);
+            float3 temp = rsMatrixMultiply(&colorMat, currentPixel.xyz);
+            temp = (clamp(temp, 0.f, 255.f) - inBlack) * overInWMinInB;
+            temp = pow(temp, (float3)gamma);
+            currentPixel.xyz = clamp(temp * outWMinOutB + outBlack, 0.f, 255.f);
 
-            uchar4 *output = OutPixel + h*width + w;
             //output.xyz = convert_uchar3(currentPixel.xyz);
             output->x = (uint8_t)currentPixel.x;
             output->y = (uint8_t)currentPixel.y;
             output->z = (uint8_t)currentPixel.z;
             output->w = input->w;
-        }
-    }
-    rsSendToClient(&count, 1, 4, 0);
-}
 
-static void horizontalBlurLevels() {
-    float4 blurredPixel = 0;
-    float4 currentPixel = 0;
-    // Horizontal blur
-    int w, h, r;
-    for(h = 0; h < height; h ++) {
-        uchar4 *output = OutPixel + h*width;
-
-        for(w = 0; w < width; w ++) {
-            blurredPixel = 0;
-
-            for(r = -radius; r <= radius; r ++) {
-                // Stepping left and right away from the pixel
-                int validW = w + r;
-                // Clamp to zero and width max() isn't exposed for ints yet
-                if(validW < 0) {
-                    validW = 0;
-                }
-                if(validW > width - 1) {
-                    validW = width - 1;
-                }
-                //int validW = rsClamp(w + r, 0, width - 1);
-
-                uchar4 *input = InPixel + h*width + validW;
-
-                float weight = gaussian[r + radius];
-                currentPixel.x = (float)(input->x);
-                currentPixel.y = (float)(input->y);
-                currentPixel.z = (float)(input->z);
-                //currentPixel.w = (float)(input->a);
-
-                blurredPixel.xyz += currentPixel.xyz * weight;
-            }
-
-            blurredPixel = levelsSaturation(blurredPixel);
-
-            output->x = (uint8_t)blurredPixel.x;
-            output->y = (uint8_t)blurredPixel.y;
-            output->z = (uint8_t)blurredPixel.z;
-            //output->a = (uint8_t)blurredPixel.w;
+            input++;
             output++;
         }
     }
 }
 
-static void initStructs() {
-    filterStruct.gaussian = gaussian;
-    filterStruct.width = width;
-    filterStruct.height = height;
-    filterStruct.radius = radius;
+static void blur() {
+    computeGaussianWeights();
+
+    FilterStruct fs;
+    fs.gaussian = gaussian;
+    fs.width = width;
+    fs.height = height;
+    fs.radius = radius;
+
+    fs.ain = rsGetAllocation(InPixel);
+    rsForEach(hBlurScript, fs.ain, rsGetAllocation(ScratchPixel), &fs);
+
+    fs.ain = rsGetAllocation(ScratchPixel);
+    rsForEach(vBlurScript, fs.ain, rsGetAllocation(OutPixel), &fs);
 }
 
 void filter() {
-    RS_DEBUG(height);
-    RS_DEBUG(width);
     RS_DEBUG(radius);
 
-    initStructs();
-
     computeColorMatrix();
 
-    if(radius == 0) {
-        processNoBlur();
-        return;
+    if(radius > 0) {
+        blur();
     }
-
-    computeGaussianWeights();
-
-    horizontalBlurLevels();
-
-    rsForEach(vBlurScript,
-              rsGetAllocation(InPixel),
-              rsGetAllocation(OutPixel),
-              &filterStruct);
+    processNoBlur();
 
     int count = 0;
     rsSendToClient(&count, 1, 4, 0);
 }
 
 void filterBenchmark() {
-    initStructs();
-
-    computeGaussianWeights();
-
-    rsForEach(hBlurScript,
-              rsGetAllocation(InPixel),
-              rsGetAllocation(OutPixel),
-              &filterStruct);
-
-    rsForEach(vBlurScript,
-              rsGetAllocation(InPixel),
-              rsGetAllocation(OutPixel),
-              &filterStruct);
+    blur();
 
     int count = 0;
     rsSendToClient(&count, 1, 4, 0);
diff --git a/libs/rs/java/ImageProcessing/res/raw/threshold_bc.bc b/libs/rs/java/ImageProcessing/res/raw/threshold_bc.bc
index 8f37fdc..2b5d254 100644
--- a/libs/rs/java/ImageProcessing/res/raw/threshold_bc.bc
+++ b/libs/rs/java/ImageProcessing/res/raw/threshold_bc.bc
Binary files differ
diff --git a/libs/rs/java/ImageProcessing/res/raw/vertical_blur.rs b/libs/rs/java/ImageProcessing/res/raw/vertical_blur.rs
index 846f515..f5f2d69 100644
--- a/libs/rs/java/ImageProcessing/res/raw/vertical_blur.rs
+++ b/libs/rs/java/ImageProcessing/res/raw/vertical_blur.rs
@@ -5,14 +5,10 @@
 
 #include "ip.rsh"
 
-uchar4 * ScratchPixel;
-
-#pragma rs export_var(ScratchPixel)
-
 void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
     uchar4 *output = (uchar4 *)v_out;
-    const uchar4 *input = (uchar4 *)v_in;
     const FilterStruct *fs = (const FilterStruct *)usrData;
+    const uchar4 *input = (const uchar4 *)rsGetElementAt(fs->ain, x, 0);
 
     float4 blurredPixel = 0;
     float4 currentPixel = 0;
@@ -27,19 +23,21 @@
             validH = fs->height - 1;
         }
 
-        uchar4 *input = ScratchPixel + validH * fs->width + x;
+        const uchar4 *i = input + validH * fs->width;
+        //const uchar4 *i = (const uchar4 *)rsGetElementAt(fs->ain, x, validH);
 
         float weight = fs->gaussian[r + fs->radius];
 
-        currentPixel.x = (float)(input->x);
-        currentPixel.y = (float)(input->y);
-        currentPixel.z = (float)(input->z);
+        currentPixel.x = (float)(i->x);
+        currentPixel.y = (float)(i->y);
+        currentPixel.z = (float)(i->z);
 
         blurredPixel.xyz += currentPixel.xyz * weight;
 #else
         int validH = rsClamp(y + r, 0, height - 1);
-        uchar4 *input = ScratchPixel + validH * width + x;
-        blurredPixel.xyz += convert_float3(input->xyz) * gaussian[r + fs->radius];
+        validH -= y;
+        uchar4 *i = input + validH * width + x;
+        blurredPixel.xyz += convert_float3(i->xyz) * gaussian[r + fs->radius];
 #endif
     }
 
diff --git a/libs/rs/java/ImageProcessing/res/raw/vertical_blur_bc.bc b/libs/rs/java/ImageProcessing/res/raw/vertical_blur_bc.bc
index af1cd8e..be5d0e4 100644
--- a/libs/rs/java/ImageProcessing/res/raw/vertical_blur_bc.bc
+++ b/libs/rs/java/ImageProcessing/res/raw/vertical_blur_bc.bc
Binary files differ
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 21c3d74..0ed1185 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -376,10 +376,7 @@
         mScratchPixelsAllocation = Allocation.createBitmapRef(mRS, mBitmapScratch);
 
         mScriptVBlur = new ScriptC_Vertical_blur(mRS, getResources(), R.raw.vertical_blur_bc, false);
-        mScriptVBlur.bind_ScratchPixel(mScratchPixelsAllocation);
-
         mScriptHBlur = new ScriptC_Horizontal_blur(mRS, getResources(), R.raw.horizontal_blur_bc, false);
-        mScriptHBlur.bind_ScratchPixel(mScratchPixelsAllocation);
 
         mScript = new ScriptC_Threshold(mRS, getResources(), R.raw.threshold_bc, false);
         mScript.set_width(mBitmapIn.getWidth());
@@ -431,8 +428,8 @@
         android.util.Log.v("Img", "Renderscript frame time core ms " + t);
 
         long javaTime = javaFilter();
-
         mBenchmarkResult.setText("RS: " + t + " ms  Java: " + javaTime + " ms");
+        //mBenchmarkResult.setText("RS: " + t + " ms");
 
         mRadius = oldRadius;
         mScript.set_radius(mRadius);
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Horizontal_blur.java b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Horizontal_blur.java
index 8ee50a8..c447b9b 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Horizontal_blur.java
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Horizontal_blur.java
@@ -26,17 +26,5 @@
         super(rs, resources, id, isRoot);
     }
 
-    private final static int mExportVarIdx_ScratchPixel = 0;
-    private Allocation mExportVar_ScratchPixel;
-    public void bind_ScratchPixel(Allocation v) {
-        mExportVar_ScratchPixel = v;
-        if(v == null) bindAllocation(null, mExportVarIdx_ScratchPixel);
-        else bindAllocation(v, mExportVarIdx_ScratchPixel);
-    }
-
-    public Allocation get_ScratchPixel() {
-        return mExportVar_ScratchPixel;
-    }
-
 }
 
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Vertical_blur.java b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Vertical_blur.java
index 0215f60..cee74d9 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Vertical_blur.java
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Vertical_blur.java
@@ -26,17 +26,5 @@
         super(rs, resources, id, isRoot);
     }
 
-    private final static int mExportVarIdx_ScratchPixel = 0;
-    private Allocation mExportVar_ScratchPixel;
-    public void bind_ScratchPixel(Allocation v) {
-        mExportVar_ScratchPixel = v;
-        if(v == null) bindAllocation(null, mExportVarIdx_ScratchPixel);
-        else bindAllocation(v, mExportVarIdx_ScratchPixel);
-    }
-
-    public Allocation get_ScratchPixel() {
-        return mExportVar_ScratchPixel;
-    }
-
 }
 
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 68eca44..629b481 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -23,6 +23,7 @@
 
 #include <sys/types.h>
 #include <sys/resource.h>
+#include <sched.h>
 
 #include <cutils/properties.h>
 
@@ -355,6 +356,49 @@
      return NULL;
 }
 
+void * Context::helperThreadProc(void *vrsc)
+{
+     Context *rsc = static_cast<Context *>(vrsc);
+     uint32_t idx = (uint32_t)android_atomic_inc(&rsc->mWorkers.mLaunchCount);
+
+     LOGE("helperThreadProc 1 %p idx=%i", rsc, idx);
+
+     rsc->mWorkers.mLaunchSignals[idx].init();
+     rsc->mWorkers.mNativeThreadId[idx] = gettid();
+
+     //cpu_set_t cpset[16];
+     //int ret = sched_getaffinity(rsc->mWorkers.mNativeThreadId[idx], sizeof(cpset), &cpset);
+     //LOGE("ret = %i", ret);
+
+//sched_setaffinity
+
+     setpriority(PRIO_PROCESS, rsc->mWorkers.mNativeThreadId[idx], rsc->mThreadPriority);
+     while(rsc->mRunning) {
+         rsc->mWorkers.mLaunchSignals[idx].wait();
+         if (rsc->mWorkers.mLaunchCallback) {
+    LOGE("helperThreadProc 4");
+            rsc->mWorkers.mLaunchCallback(rsc->mWorkers.mLaunchData, idx);
+         }
+    LOGE("helperThreadProc 5");
+         android_atomic_dec(&rsc->mWorkers.mRunningCount);
+         rsc->mWorkers.mCompleteSignal.set();
+     }
+     return NULL;
+}
+
+void Context::launchThreads(WorkerCallback_t cbk, void *data)
+{
+    mWorkers.mLaunchData = data;
+    mWorkers.mLaunchCallback = cbk;
+    mWorkers.mRunningCount = (int)mWorkers.mCount;
+    for (uint32_t ct = 0; ct < mWorkers.mCount; ct++) {
+        mWorkers.mLaunchSignals[ct].set();
+    }
+    while(mWorkers.mRunningCount) {
+        mWorkers.mCompleteSignal.wait();
+    }
+}
+
 void Context::setPriority(int32_t p)
 {
     // Note: If we put this in the proper "background" policy
@@ -371,7 +415,10 @@
         // success; reset the priority as well
     }
 #else
-        setpriority(PRIO_PROCESS, mNativeThreadId, p);
+    setpriority(PRIO_PROCESS, mNativeThreadId, p);
+    for (uint32_t ct=0; ct < mWorkers.mCount; ct++) {
+        setpriority(PRIO_PROCESS, mWorkers.mNativeThreadId[ct], p);
+    }
 #endif
 }
 
@@ -421,10 +468,26 @@
     timerInit();
     timerSet(RS_TIMER_INTERNAL);
 
-    LOGV("RS Launching thread");
+    LOGV("RS Launching thread(s)");
+    mWorkers.mCount = 2;
+    mWorkers.mThreadId = (pthread_t *) calloc(mWorkers.mCount, sizeof(pthread_t));
+    mWorkers.mNativeThreadId = (pid_t *) calloc(mWorkers.mCount, sizeof(pid_t));
+    mWorkers.mLaunchSignals = new Signal[mWorkers.mCount];
+    mWorkers.mLaunchCallback = NULL;
     status = pthread_create(&mThreadId, &threadAttr, threadProc, this);
     if (status) {
         LOGE("Failed to start rs context thread.");
+        return;
+    }
+    mWorkers.mRunningCount = 0;
+    mWorkers.mLaunchCount = 0;
+    for (uint32_t ct=0; ct < mWorkers.mCount; ct++) {
+        status = pthread_create(&mWorkers.mThreadId[ct], &threadAttr, helperThreadProc, this);
+        if (status) {
+            mWorkers.mCount = ct;
+            LOGE("Created fewer than expected number of RS threads.");
+            break;
+        }
     }
 
     while(!mRunning) {
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 06433a1..98ad3a4 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -65,6 +65,7 @@
         Script * mScript;
     };
 
+    typedef void (*WorkerCallback_t)(void *usr, uint32_t idx);
 
     //StructuredAllocationContext mStateAllocation;
     ElementState mStateElement;
@@ -172,6 +173,8 @@
 
     bool ext_OES_texture_npot() const {return mGL.OES_texture_npot;}
 
+    void launchThreads(WorkerCallback_t cbk, void *data);
+
 protected:
     Device *mDev;
 
@@ -222,6 +225,20 @@
     pthread_t mThreadId;
     pid_t mNativeThreadId;
 
+    struct Workers {
+        volatile int mRunningCount;
+        volatile int mLaunchCount;
+        uint32_t mCount;
+        pthread_t *mThreadId;
+        pid_t *mNativeThreadId;
+        Signal mCompleteSignal;
+
+        Signal *mLaunchSignals;
+        WorkerCallback_t mLaunchCallback;
+        void *mLaunchData;
+    };
+    Workers mWorkers;
+
     ObjectBaseRef<Script> mRootScript;
     ObjectBaseRef<ProgramFragment> mFragment;
     ObjectBaseRef<ProgramVertex> mVertex;
@@ -248,6 +265,7 @@
     uint32_t runRootScript();
 
     static void * threadProc(void *);
+    static void * helperThreadProc(void *);
 
     ANativeWindow *mWndSurface;
 
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index b87ac28..9693b16e 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -137,72 +137,155 @@
 }
 
 
+typedef struct {
+    Context *rsc;
+    ScriptC *script;
+    const Allocation * ain;
+    Allocation * aout;
+    const void * usr;
+
+    uint32_t mSliceSize;
+    volatile int mSliceNum;
+
+    const uint8_t *ptrIn;
+    uint32_t eStrideIn;
+    uint8_t *ptrOut;
+    uint32_t eStrideOut;
+
+    uint32_t xStart;
+    uint32_t xEnd;
+    uint32_t yStart;
+    uint32_t yEnd;
+    uint32_t zStart;
+    uint32_t zEnd;
+    uint32_t arrayStart;
+    uint32_t arrayEnd;
+
+    uint32_t dimX;
+    uint32_t dimY;
+    uint32_t dimZ;
+    uint32_t dimArray;
+} MTLaunchStruct;
+typedef int (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
+
+static void wc_xy(void *usr, uint32_t idx)
+{
+    MTLaunchStruct *mtls = (MTLaunchStruct *)usr;
+    LOGE("usr %p, idx %i", usr, idx);
+
+    while (1) {
+        uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
+        uint32_t yStart = mtls->yStart + slice * mtls->mSliceSize;
+        uint32_t yEnd = yStart + mtls->mSliceSize;
+        yEnd = rsMin(yEnd, mtls->yEnd);
+        if (yEnd <= yStart) {
+            return;
+        }
+
+        //LOGE("usr idx %i, x %i,%i  y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd);
+
+        for (uint32_t y = yStart; y < yEnd; y++) {
+            uint32_t offset = mtls->dimX * y;
+            uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * offset);
+            const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * offset);
+
+            for (uint32_t x = mtls->xStart; x < mtls->xEnd; x++) {
+                ((rs_t)mtls->script->mProgram.mRoot) (xPtrIn, xPtrOut, mtls->usr, x, y, 0, 0);
+                xPtrIn += mtls->eStrideIn;
+                xPtrOut += mtls->eStrideOut;
+            }
+        }
+    }
+
+}
+
 void ScriptC::runForEach(Context *rsc,
                          const Allocation * ain,
                          Allocation * aout,
                          const void * usr,
                          const RsScriptCall *sc)
 {
-    uint32_t dimX = ain->getType()->getDimX();
-    uint32_t dimY = ain->getType()->getDimY();
-    uint32_t dimZ = ain->getType()->getDimZ();
-    uint32_t dimA = 0;//ain->getType()->getDimArray();
+    MTLaunchStruct mtls;
+    memset(&mtls, 0, sizeof(mtls));
 
-    uint32_t xStart = 0;
-    uint32_t xEnd = 0;
-    uint32_t yStart = 0;
-    uint32_t yEnd = 0;
-    uint32_t zStart = 0;
-    uint32_t zEnd = 0;
-    uint32_t arrayStart = 0;
-    uint32_t arrayEnd = 0;
+    if (ain) {
+        mtls.dimX = ain->getType()->getDimX();
+        mtls.dimY = ain->getType()->getDimY();
+        mtls.dimZ = ain->getType()->getDimZ();
+        //mtls.dimArray = ain->getType()->getDimArray();
+    } else if (aout) {
+        mtls.dimX = aout->getType()->getDimX();
+        mtls.dimY = aout->getType()->getDimY();
+        mtls.dimZ = aout->getType()->getDimZ();
+        //mtls.dimArray = aout->getType()->getDimArray();
+    } else {
+        rsc->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
+        return;
+    }
 
     if (!sc || (sc->xEnd == 0)) {
-        xStart = 0;
-        xEnd = ain->getType()->getDimX();
+        mtls.xEnd = mtls.dimX;
     } else {
-        rsAssert(xStart < dimX);
-        rsAssert(xEnd <= dimX);
+        rsAssert(sc->xStart < mtls.dimX);
+        rsAssert(sc->xEnd <= mtls.dimX);
         rsAssert(sc->xStart < sc->xEnd);
-        xStart = rsMin(dimX, sc->xStart);
-        xEnd = rsMin(dimX, sc->xEnd);
-        if (xStart >= xEnd) return;
+        mtls.xStart = rsMin(mtls.dimX, sc->xStart);
+        mtls.xEnd = rsMin(mtls.dimX, sc->xEnd);
+        if (mtls.xStart >= mtls.xEnd) return;
     }
 
     if (!sc || (sc->yEnd == 0)) {
-        yStart = 0;
-        yEnd = ain->getType()->getDimY();
+        mtls.yEnd = mtls.dimY;
     } else {
-        rsAssert(yStart < dimY);
-        rsAssert(yEnd <= dimY);
+        rsAssert(sc->yStart < mtls.dimY);
+        rsAssert(sc->yEnd <= mtls.dimY);
         rsAssert(sc->yStart < sc->yEnd);
-        yStart = rsMin(dimY, sc->yStart);
-        yEnd = rsMin(dimY, sc->yEnd);
-        if (yStart >= yEnd) return;
+        mtls.yStart = rsMin(mtls.dimY, sc->yStart);
+        mtls.yEnd = rsMin(mtls.dimY, sc->yEnd);
+        if (mtls.yStart >= mtls.yEnd) return;
     }
 
-    xEnd = rsMax((uint32_t)1, xEnd);
-    yEnd = rsMax((uint32_t)1, yEnd);
-    zEnd = rsMax((uint32_t)1, zEnd);
-    arrayEnd = rsMax((uint32_t)1, arrayEnd);
+    mtls.xEnd = rsMax((uint32_t)1, mtls.xEnd);
+    mtls.yEnd = rsMax((uint32_t)1, mtls.yEnd);
+    mtls.zEnd = rsMax((uint32_t)1, mtls.zEnd);
+    mtls.arrayEnd = rsMax((uint32_t)1, mtls.arrayEnd);
 
     rsAssert(ain->getType()->getDimZ() == 0);
 
     setupScript(rsc);
     Script * oldTLS = setTLS(this);
 
-    typedef int (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
 
-    const uint8_t *ptrIn = (const uint8_t *)ain->getPtr();
-    uint32_t eStrideIn = ain->getType()->getElementSizeBytes();
+    mtls.rsc = rsc;
+    mtls.ain = ain;
+    mtls.aout = aout;
+    mtls.script = this;
+    mtls.usr = usr;
+    mtls.mSliceSize = 10;
+    mtls.mSliceNum = 0;
 
-    uint8_t *ptrOut = NULL;
-    uint32_t eStrideOut = 0;
-    if (aout) {
-        ptrOut = (uint8_t *)aout->getPtr();
-        eStrideOut = aout->getType()->getElementSizeBytes();
+    mtls.ptrIn = NULL;
+    mtls.eStrideIn = 0;
+    if (ain) {
+        mtls.ptrIn = (const uint8_t *)ain->getPtr();
+        mtls.eStrideIn = ain->getType()->getElementSizeBytes();
     }
 
+    mtls.ptrOut = NULL;
+    mtls.eStrideOut = 0;
+    if (aout) {
+        mtls.ptrOut = (uint8_t *)aout->getPtr();
+        mtls.eStrideOut = aout->getType()->getElementSizeBytes();
+    }
+
+
+    {
+        LOGE("launch 1");
+        rsc->launchThreads(wc_xy, &mtls);
+        LOGE("launch 2");
+    }
+
+/*
     for (uint32_t ar = arrayStart; ar < arrayEnd; ar++) {
         for (uint32_t z = zStart; z < zEnd; z++) {
             for (uint32_t y = yStart; y < yEnd; y++) {
@@ -221,7 +304,7 @@
         }
 
     }
-
+*/
     setTLS(oldTLS);
 }
 
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 8d9ca9f..9c29ca6 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -329,6 +329,29 @@
     return a->getType()->getDimFaces();
 }
 
+const void * SC_getElementAtX(RsAllocation va, uint32_t x)
+{
+    const Allocation *a = static_cast<const Allocation *>(va);
+    const Type *t = a->getType();
+    const uint8_t *p = (const uint8_t *)a->getPtr();
+    return &p[t->getElementSizeBytes() * x];
+}
+
+const void * SC_getElementAtXY(RsAllocation va, uint32_t x, uint32_t y)
+{
+    const Allocation *a = static_cast<const Allocation *>(va);
+    const Type *t = a->getType();
+    const uint8_t *p = (const uint8_t *)a->getPtr();
+    return &p[t->getElementSizeBytes() * (x + y*t->getDimX())];
+}
+
+const void * SC_getElementAtXYZ(RsAllocation va, uint32_t x, uint32_t y, uint32_t z)
+{
+    const Allocation *a = static_cast<const Allocation *>(va);
+    const Type *t = a->getType();
+    const uint8_t *p = (const uint8_t *)a->getPtr();
+    return &p[t->getElementSizeBytes() * (x + y*t->getDimX())];
+}
 
 
 static void SC_debugF(const char *s, float f) {
@@ -350,6 +373,10 @@
     LOGE("%s %i  0x%x", s, i, i);
 }
 
+static void SC_debugP(const char *s, const void *p) {
+    LOGE("%s %p", s, p);
+}
+
 static uint32_t SC_toClient(void *data, int cmdID, int len, int waitForSpace)
 {
     GET_TLS();
@@ -433,12 +460,18 @@
     { "rsAllocationGetDimFaces", (void *)&SC_allocGetDimFaces },
     { "rsGetAllocation", (void *)&SC_getAllocation },
 
+    { "_Z14rsGetElementAt13rs_allocationj", (void *)&SC_getElementAtX },
+    { "_Z14rsGetElementAt13rs_allocationjj", (void *)&SC_getElementAtXY },
+    { "_Z14rsGetElementAt13rs_allocationjjj", (void *)&SC_getElementAtXYZ },
+
+
     // Debug
     { "_Z7rsDebugPKcf", (void *)&SC_debugF },
     { "_Z7rsDebugPKcDv2_f", (void *)&SC_debugFv2 },
     { "_Z7rsDebugPKcDv3_f", (void *)&SC_debugFv3 },
     { "_Z7rsDebugPKcDv4_f", (void *)&SC_debugFv4 },
     { "_Z7rsDebugPKci", (void *)&SC_debugI32 },
+    { "_Z7rsDebugPKcPKv", (void *)&SC_debugP },
     //extern void __attribute__((overloadable))rsDebug(const char *, const void *);
 
 
diff --git a/libs/rs/rsUtils.h b/libs/rs/rsUtils.h
index 0a37a5b..17feb22 100644
--- a/libs/rs/rsUtils.h
+++ b/libs/rs/rsUtils.h
@@ -30,6 +30,7 @@
 #include <stdlib.h>
 #include <pthread.h>
 #include <time.h>
+#include <cutils/atomic.h>
 
 #ifndef ANDROID_RS_BUILD_FOR_HOST
 #include <EGL/egl.h>
diff --git a/libs/rs/scriptc/rs_math.rsh b/libs/rs/scriptc/rs_math.rsh
index e11c832..bd6e5a9 100644
--- a/libs/rs/scriptc/rs_math.rsh
+++ b/libs/rs/scriptc/rs_math.rsh
@@ -14,6 +14,12 @@
 extern uint32_t rsAllocationGetDimLOD(rs_allocation);
 extern uint32_t rsAllocationGetDimFaces(rs_allocation);
 
+extern const void * __attribute__((overloadable))
+    rsGetElementAt(rs_allocation, uint32_t x);
+extern const void * __attribute__((overloadable))
+    rsGetElementAt(rs_allocation, uint32_t x, uint32_t y);
+extern const void * __attribute__((overloadable))
+    rsGetElementAt(rs_allocation, uint32_t x, uint32_t y, uint32_t z);
 
 
 // Debugging
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 1674221..30597320 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -425,6 +425,23 @@
         }
     }
 
+    public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, RemoteViews views, int viewId) {
+        if (appWidgetIds == null) {
+            return;
+        }
+        if (appWidgetIds.length == 0) {
+            return;
+        }
+        final int N = appWidgetIds.length;
+
+        synchronized (mAppWidgetIds) {
+            for (int i=0; i<N; i++) {
+                AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
+                notifyAppWidgetViewDataChangedInstanceLocked(id, views, viewId);
+            }
+        }
+    }
+
     public void updateAppWidgetProvider(ComponentName provider, RemoteViews views) {
         synchronized (mAppWidgetIds) {
             Provider p = lookupProviderLocked(provider);
@@ -462,6 +479,27 @@
         }
     }
 
+    void notifyAppWidgetViewDataChangedInstanceLocked(AppWidgetId id, RemoteViews views, int viewId) {
+        // allow for stale appWidgetIds and other badness
+        // lookup also checks that the calling process can access the appWidgetId
+        // drop unbound appWidgetIds (shouldn't be possible under normal circumstances)
+        if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) {
+            id.views = views;
+
+            // is anyone listening?
+            if (id.host.callbacks != null) {
+                try {
+                    // the lock is held, but this is a oneway call
+                    id.host.callbacks.viewDataChanged(id.appWidgetId, views, viewId);
+                } catch (RemoteException e) {
+                    // It failed; remove the callback. No need to prune because
+                    // we know that this host is still referenced by this instance.
+                    id.host.callbacks = null;
+                }
+            }
+        }
+    }
+
     public int[] startListening(IAppWidgetHost callbacks, String packageName, int hostId,
             List<RemoteViews> updatedViews) {
         int callingUid = enforceCallingUid(packageName);