Merge change 20706

* changes:
  Improve Browser performance by 1-2%. To address domain sanity bug, http://b/issue?id=1022797, we decoded/encoded the url for each request. As the url can be long, getBytes() and String.init are taking 1.5% in nytimes.com and 2.4% in cnn.com. By doing a simple URL encoding test, we can shave 1-2 secs thread time during loading.
diff --git a/Android.mk b/Android.mk
index 15ba27f..a9caa20 100644
--- a/Android.mk
+++ b/Android.mk
@@ -114,6 +114,8 @@
 	core/java/android/os/IParentalControlCallback.aidl \
 	core/java/android/os/IPermissionController.aidl \
 	core/java/android/os/IPowerManager.aidl \
+    core/java/android/service/wallpaper/IWallpaperConnection.aidl \
+    core/java/android/service/wallpaper/IWallpaperEngine.aidl \
     core/java/android/service/wallpaper/IWallpaperService.aidl \
 	core/java/android/text/IClipboard.aidl \
 	core/java/android/view/accessibility/IAccessibilityManager.aidl \
diff --git a/api/current.xml b/api/current.xml
index 9a635f6..69d4d5c 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -177,6 +177,17 @@
  visibility="public"
 >
 </field>
+<field name="BIND_WALLPAPER"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.BIND_WALLPAPER&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="BLUETOOTH"
  type="java.lang.String"
  transient="false"
@@ -9359,6 +9370,17 @@
  visibility="public"
 >
 </field>
+<field name="windowShowWallpaper"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843426"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="windowSoftInputMode"
  type="int"
  transient="false"
@@ -14991,6 +15013,39 @@
  visibility="public"
 >
 </field>
+<field name="Theme_Wallpaper"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973937"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="Theme_Wallpaper_NoTitleBar"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973938"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="Theme_Wallpaper_NoTitleBar_Fullscreen"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973939"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="Widget"
  type="int"
  transient="false"
@@ -26763,17 +26818,6 @@
 <exception name="IOException" type="java.io.IOException">
 </exception>
 </method>
-<method name="get"
- return="android.graphics.drawable.Drawable"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="getDesiredMinimumHeight"
  return="int"
  abstract="false"
@@ -26796,7 +26840,7 @@
  visibility="public"
 >
 </method>
-<method name="peek"
+<method name="getDrawable"
  return="android.graphics.drawable.Drawable"
  abstract="false"
  native="false"
@@ -26807,8 +26851,21 @@
  visibility="public"
 >
 </method>
-<method name="set"
- return="void"
+<method name="getInstance"
+ return="android.app.WallpaperManager"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="peekDrawable"
+ return="android.graphics.drawable.Drawable"
  abstract="false"
  native="false"
  synchronized="false"
@@ -26817,12 +26874,8 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="resid" type="int">
-</parameter>
-<exception name="IOException" type="java.io.IOException">
-</exception>
 </method>
-<method name="set"
+<method name="setBitmap"
  return="void"
  abstract="false"
  native="false"
@@ -26837,7 +26890,22 @@
 <exception name="IOException" type="java.io.IOException">
 </exception>
 </method>
-<method name="set"
+<method name="setResource"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="resid" type="int">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="setStream"
  return="void"
  abstract="false"
  native="false"
@@ -26852,7 +26920,24 @@
 <exception name="IOException" type="java.io.IOException">
 </exception>
 </method>
-<method name="setDimensionHints"
+<method name="setWallpaperOffsets"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="windowToken" type="android.os.IBinder">
+</parameter>
+<parameter name="xOffset" type="float">
+</parameter>
+<parameter name="yOffset" type="float">
+</parameter>
+</method>
+<method name="suggestDesiredDimensions"
  return="void"
  abstract="false"
  native="false"
@@ -29200,7 +29285,7 @@
  visibility="public"
 >
 </method>
-<method name="newCountQuery"
+<method name="newAssertQuery"
  return="android.content.ContentProviderOperation.Builder"
  abstract="false"
  native="false"
@@ -115993,50 +116078,6 @@
 </implements>
 </interface>
 </package>
-<package name="android.service.wallpaper"
->
-<class name="WallpaperService"
- extends="android.app.Service"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="WallpaperService"
- type="android.service.wallpaper.WallpaperService"
- 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="true"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="intent" type="android.content.Intent">
-</parameter>
-</method>
-<field name="SERVICE_INTERFACE"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.service.wallpaper.WallpaperService&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-</class>
-</package>
 <package name="android.speech"
 >
 <class name="RecognizerIntent"
@@ -157363,6 +157404,28 @@
  visibility="public"
 >
 </field>
+<field name="FLAG_SHOW_WALLPAPER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1048576"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FLAG_SHOW_WHEN_LOCKED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="524288"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FLAG_TOUCHABLE_WHEN_WAKING"
  type="int"
  transient="false"
@@ -157913,6 +157976,17 @@
  visibility="public"
 >
 </field>
+<field name="TYPE_WALLPAPER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2013"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="alpha"
  type="float"
  transient="false"
@@ -168164,6 +168238,21 @@
  visibility="public"
 >
 </method>
+<method name="postUrl"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="java.lang.String">
+</parameter>
+<parameter name="postData" type="byte[]">
+</parameter>
+</method>
 <method name="refreshPlugins"
  return="void"
  abstract="false"
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index ee3ec1a..8c15d0b 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -268,7 +268,7 @@
 
     private void printRestoreSets(RestoreSet[] sets) {
         for (RestoreSet s : sets) {
-            System.out.println("  " + s.token + " : " + s.name);
+            System.out.println("  " + Long.toHexString(s.token) + " : " + s.name);
         }
     }
 
@@ -294,7 +294,7 @@
     private void doRestore() {
         long token;
         try {
-            token = Long.parseLong(nextArg());
+            token = Long.parseLong(nextArg(), 16);
         } catch (NumberFormatException e) {
             showUsage();
             return;
@@ -311,12 +311,13 @@
                 return;
             }
             RestoreSet[] sets = mRestore.getAvailableRestoreSets();
-            for (RestoreSet s : sets) {
-                if (s.token == token) {
-                    System.out.println("Scheduling restore: " + s.name);
-                    mRestore.performRestore(token, observer);
-                    didRestore = true;
-                    break;
+            if (sets != null) {
+                for (RestoreSet s : sets) {
+                    if (s.token == token) {
+                        System.out.println("Scheduling restore: " + s.name);
+                        didRestore = (mRestore.performRestore(token, observer) == 0);
+                        break;
+                    }
                 }
             }
             if (!didRestore) {
@@ -327,21 +328,27 @@
                     printRestoreSets(sets);
                 }
             }
+
+            // if we kicked off a restore successfully, we have to wait for it
+            // to complete before we can shut down the restore session safely
+            if (didRestore) {
+                synchronized (observer) {
+                    while (!observer.done) {
+                        try {
+                            observer.wait();
+                        } catch (InterruptedException ex) {
+                        }
+                    }
+                }
+            }
+
+            // once the restore has finished, close down the session and we're done
             mRestore.endRestoreSession();
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(BMGR_NOT_RUNNING_ERR);
         }
 
-        // now wait for it to be done
-        synchronized (observer) {
-            while (!observer.done) {
-                try {
-                    observer.wait();
-                } catch (InterruptedException ex) {
-                }
-            }
-        }
         System.out.println("done");
     }
 
diff --git a/cmds/keystore/netkeystore.c b/cmds/keystore/netkeystore.c
index 637e0d8..bdd5960 100644
--- a/cmds/keystore/netkeystore.c
+++ b/cmds/keystore/netkeystore.c
@@ -242,6 +242,7 @@
 {
     struct timeval tv;
     tv.tv_sec = READ_TIMEOUT;
+    tv.tv_usec = 0;
     if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,  sizeof tv))
     {
         LOGE("setsockopt failed");
diff --git a/cmds/keystore/netkeystore.h b/cmds/keystore/netkeystore.h
index a87a667..d80ddae 100644
--- a/cmds/keystore/netkeystore.h
+++ b/cmds/keystore/netkeystore.h
@@ -19,6 +19,7 @@
 #define __NETKEYSTORE_H__
 
 #include <stdio.h>
+#include <arpa/inet.h>
 #include <cutils/sockets.h>
 #include <cutils/log.h>
 
@@ -68,6 +69,8 @@
         LOGE("failed to read header\n");
         return -1;
     }
+    cmd->len = ntohl(cmd->len);
+    cmd->opcode = ntohl(cmd->opcode);
     if (cmd->len > BUFFER_MAX) {
         LOGE("invalid size %d\n", cmd->len);
         return -1;
@@ -82,11 +85,14 @@
 
 static inline int write_marshal(int s, LPC_MARSHAL *cmd)
 {
+    int len = cmd->len;
+    cmd->len = htonl(cmd->len);
+    cmd->opcode = htonl(cmd->opcode);
     if (writex(s, cmd, 2 * sizeof(uint32_t))) {
         LOGE("failed to write marshal header\n");
         return -1;
     }
-    if (writex(s, cmd->data, cmd->len)) {
+    if (writex(s, cmd->data, len)) {
         LOGE("failed to write marshal data\n");
         return -1;
     }
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index 8ac9557..7e71088 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -514,12 +514,12 @@
     
     @Override
     public Drawable getWallpaper() {
-        return getWallpaperManager().get();
+        return getWallpaperManager().getDrawable();
     }
 
     @Override
     public Drawable peekWallpaper() {
-        return getWallpaperManager().peek();
+        return getWallpaperManager().peekDrawable();
     }
 
     @Override
@@ -534,12 +534,12 @@
 
     @Override
     public void setWallpaper(Bitmap bitmap) throws IOException  {
-        getWallpaperManager().set(bitmap);
+        getWallpaperManager().setBitmap(bitmap);
     }
 
     @Override
     public void setWallpaper(InputStream data) throws IOException {
-        getWallpaperManager().set(data);
+        getWallpaperManager().setStream(data);
     }
 
     @Override
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 1ed9b9f..7741668 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -18,6 +18,7 @@
 
 import android.os.ParcelFileDescriptor;
 import android.app.IWallpaperManagerCallback;
+import android.content.ComponentName;
 
 /** @hide */
 interface IWallpaperManager {
@@ -28,6 +29,11 @@
     ParcelFileDescriptor setWallpaper(String name);
     
     /**
+     * Set the live wallpaper.
+     */
+    void setWallpaperComponent(in ComponentName name);
+    
+    /**
      * Get the wallpaper.
      */
     ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb);
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 9c20a4b..b75bec2 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -67,6 +67,7 @@
 import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.TextView;
+import android.widget.ListAdapter;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.AdapterView.OnItemSelectedListener;
 
@@ -1750,7 +1751,7 @@
                 // case we want to dismiss the soft keyboard so the user can see the rest of the
                 // shortcuts.
                 if (isInputMethodNotNeeded() ||
-                        (isEmpty() && getDropDownChildCount() >= getAdapter().getCount())) {
+                        (isEmpty() && getDropDownChildCount() >= getAdapterCount())) {
                     mSearchDialog.cancel();
                     return true;
                 }
@@ -1758,6 +1759,11 @@
             }
             return false;
         }
+
+        private int getAdapterCount() {
+            final ListAdapter adapter = getAdapter();
+            return adapter == null ? 0 : adapter.getCount();
+        }
     }
     
     protected boolean handleBackKey(int keyCode, KeyEvent event) {
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index fd559d6..7ad6423 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -40,7 +40,7 @@
  * methods and the the {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH}
  * {@link android.content.Intent Intent}.  This class does provide a basic
  * overview of search services and how to integrate them with your activities.
- * If you do require direct access to the Search Manager, do not instantiate 
+ * If you do require direct access to the SearchManager, do not instantiate 
  * this class directly; instead, retrieve it through
  * {@link android.content.Context#getSystemService
  * context.getSystemService(Context.SEARCH_SERVICE)}.
@@ -49,9 +49,10 @@
  * <ol>
  * <li><a href="#DeveloperGuide">Developer Guide</a>
  * <li><a href="#HowSearchIsInvoked">How Search Is Invoked</a>
- * <li><a href="#QuerySearchApplications">Query-Search Applications</a>
- * <li><a href="#FilterSearchApplications">Filter-Search Applications</a>
+ * <li><a href="#ImplementingSearchForYourApp">Implementing Search for Your App</a>
  * <li><a href="#Suggestions">Search Suggestions</a>
+ * <li><a href="#ExposingSearchSuggestionsToQuickSearchBox">Exposing Search Suggestions to
+ * Quick Search Box</a></li>
  * <li><a href="#ActionKeys">Action Keys</a>
  * <li><a href="#SearchabilityMetadata">Searchability Metadata</a>
  * <li><a href="#PassingSearchContext">Passing Search Context</a>
@@ -62,37 +63,18 @@
  * <h3>Developer Guide</h3>
  * 
  * <p>The ability to search for user, system, or network based data is considered to be
- * a core user-level feature of the android platform.  At any time, the user should be
+ * a core user-level feature of the Android platform.  At any time, the user should be
  * able to use a familiar command, button, or keystroke to invoke search, and the user
- * should be able to search any data which is available to them.  The goal is to make search 
- * appear to the user as a seamless, system-wide feature.
+ * should be able to search any data which is available to them.
  * 
- * <p>In terms of implementation, there are three broad classes of Applications:
- * <ol>
- * <li>Applications that are not inherently searchable</li>
- * <li>Query-Search Applications</li>
- * <li>Filter-Search Applications</li>
- * </ol>
- * <p>These categories, as well as related topics, are discussed in
- * the sections below.
+ * <p>To make search appear to the user as a seamless system-wide feature, the application
+ * framework centrally controls it, offering APIs to individual applications to control how they
+ * are searched. Applications can customize how search is invoked, how the search dialog looks,
+ * and what type of search results are available, including suggestions that are available as the
+ * user types.
  *
- * <p>Even if your application is not <i>searchable</i>, it can still support the invocation of
- * search.  Please review the section <a href="#HowSearchIsInvoked">How Search Is Invoked</a>
- * for more information on how to support this.
- * 
- * <p>Many applications are <i>searchable</i>.  These are 
- * the applications which can convert a query string into a list of results.  
- * Within this subset, applications can be grouped loosely into two families:  
- * <ul><li><i>Query Search</i> applications perform batch-mode searches - each query string is 
- * converted to a list of results.</li>
- * <li><i>Filter Search</i> applications provide live filter-as-you-type searches.</li></ul>
- * <p>Generally speaking, you would use query search for network-based data, and filter 
- * search for local data, but this is not a hard requirement and applications 
- * are free to use the model that fits them best (or invent a new model).
- * <p>It should be clear that the search implementation decouples "search 
- * invocation" from "searchable".  This satisfies the goal of making search appear
- * to be "universal".  The user should be able to launch any search from 
- * almost any context.
+ * <p>Even applications which are not searchable will by default support the invocation of
+ * search to trigger Quick Search Box, the system's 'global search'.
  * 
  * <a name="HowSearchIsInvoked"></a>
  * <h3>How Search Is Invoked</h3>
@@ -100,14 +82,15 @@
  * <p>Unless impossible or inapplicable, all applications should support
  * invoking the search UI.  This means that when the user invokes the search command, 
  * a search UI will be presented to them.  The search command is currently defined as a menu
- * item called "Search" (with an alphabetic shortcut key of "S"), or on some devices, a dedicated
+ * item called "Search" (with an alphabetic shortcut key of "S"), or on many devices, a dedicated
  * search button key.
- * <p>If your application is not inherently searchable, you can also allow the search UI
- * to be invoked in a "web search" mode.  If the user enters a search term and clicks the 
- * "Search" button, this will bring the browser to the front and will launch a web-based
+ * <p>If your application is not inherently searchable, the default implementation will cause
+ * the search UI to be invoked in a "global search" mode known as Quick Search Box.  As the user
+ * types, search suggestions from across the device and the web will be surfaced, and if they
+ * click the "Search" button, this will bring the browser to the front and will launch a web-based
  * search.  The user will be able to click the "Back" button and return to your application.
  * <p>In general this is implemented by your activity, or the {@link android.app.Activity Activity}
- * base class, which captures the search command and invokes the Search Manager to 
+ * base class, which captures the search command and invokes the SearchManager to 
  * display and operate the search UI.  You can also cause the search UI to be presented in response
  * to user keystrokes in your activity (for example, to instantly start filter searching while
  * viewing a list and typing any key).
@@ -124,7 +107,7 @@
  * button or menu item - and invoking the search UI directly.</li>
  * <li>You can provide a <i>type-to-search</i> feature, in which search is invoked automatically
  * when the user enters any characters.</li>
- * <li>Even if your application is not inherently searchable, you can allow web search, 
+ * <li>Even if your application is not inherently searchable, you can allow global search, 
  * via the search key (or even via a search menu item).
  * <li>You can disable search entirely.  This should only be used in very rare circumstances,
  * as search is a system-wide feature and users will expect it to be available in all contexts.</li>
@@ -148,21 +131,23 @@
  * setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);   // search within your activity
  * setDefaultKeyMode(DEFAULT_KEYS_SEARCH_GLOBAL);  // search using platform global search</pre>
  * 
- * <p><b>How to enable web-based search.</b>  In addition to searching within your activity or
- * application, you can also use the Search Manager to invoke a platform-global search, typically
- * a web search.  There are two ways to do this:
+ * <p><b>How to enable global search with Quick Search Box.</b>  In addition to searching within
+ * your activity or application, you can also use the Search Manager to invoke a platform-global
+ * search, which uses Quick Search Box to search across the device and the web. There are two ways
+ * to do this:
  * <ul><li>You can simply define "search" within your application or activity to mean global search.
  * This is described in more detail in the 
  * <a href="#SearchabilityMetadata">Searchability Metadata</a> section.  Briefly, you will
  * add a single meta-data entry to your manifest, declaring that the default search
  * for your application is "*".  This indicates to the system that no application-specific
  * search activity is provided, and that it should launch web-based search instead.</li>
- * <li>You can specify this at invocation time via default keys (see above), overriding
- * {@link android.app.Activity#onSearchRequested}, or via a direct call to 
- * {@link android.app.Activity#startSearch}.  This is most useful if you wish to provide local
- * searchability <i>and</i> access to global search.</li></ul> 
+ * <li>Simply do nothing and the default implementation of
+ * {@link android.app.Activity#onSearchRequested} will cause global search to be triggered.
+ * (You can also always trigger search via a direct call to {@link android.app.Activity#startSearch}.
+ * This is most useful if you wish to provide local searchability <i>and</i> access to global
+ * search.)</li></ul> 
  * 
- * <p><b>How to disable search from your activity.</b>  search is a system-wide feature and users
+ * <p><b>How to disable search from your activity.</b> Search is a system-wide feature and users
  * will expect it to be available in all contexts.  If your UI design absolutely precludes
  * launching search, override {@link android.app.Activity#onSearchRequested onSearchRequested}
  * as shown:
@@ -172,7 +157,7 @@
  *    return false;
  * }</pre> 
  * 
- * <p><b>Managing focus and knowing if Search is active.</b>  The search UI is not a separate
+ * <p><b>Managing focus and knowing if search is active.</b>  The search UI is not a separate
  * activity, and when the UI is invoked or dismissed, your activity will not typically be paused,
  * resumed, or otherwise notified by the methods defined in 
  * <a href="{@docRoot}guide/topics/fundamentals.html#actlife">Application Fundamentals: 
@@ -194,17 +179,10 @@
  * the search UI.  More details on searchable activities and search intents are provided in the
  * sections below.
  *
- * <a name="QuerySearchApplications"></a>
- * <h3>Query-Search Applications</h3>
- * 
- * <p>Query-search applications are those that take a single query (e.g. a search
- * string) and present a set of results that may fit.  Primary examples include
- * web queries, map lookups, or email searches (with the common thread being
- * network query dispatch).  It may also be the case that certain local searches
- * are treated this way.  It's up to the application to decide.
+ * <a name="ImplementingSearchForYourApp"></a>
+ * <h3>Implementing Search for Your App</h3>
  *
- * <p><b>What you need to do:</b>  The following steps are necessary in order to
- * implement query search.
+ * <p>The following steps are necessary in order to implement search.
  * <ul>
  * <li>Implement search invocation as described above.  (Strictly speaking, 
  * these are decoupled, but it would make little sense to be "searchable" but not 
@@ -220,16 +198,16 @@
  * {@link #QUERY getStringExtra(SearchManager.QUERY)}.</li>
  * <li>To identify and support your searchable activity, you'll need to 
  * provide an XML file providing searchability configuration parameters, a reference to that 
- * in your searchable activity's <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a>
- * entry, and an intent-filter declaring that you can 
- * receive ACTION_SEARCH intents.  This is described in more detail in the 
- * <a href="#SearchabilityMetadata">Searchability Metadata</a> section.</li>
- * <li>Your <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> also needs a metadata entry
- * providing a global reference to the searchable activity.  This is the "glue" directing the search
- * UI, when invoked from any of your <i>other</i> activities, to use your application as the
- * default search context.  This is also described in more detail in the 
+ * in your searchable activity's
+ * <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> entry, and an
+ * intent-filter declaring that you can receive ACTION_SEARCH intents. This is described in more
+ * detail in the <a href="#SearchabilityMetadata">Searchability Metadata</a> section.</li>
+ * <li>Your <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> also needs a
+ * metadata entry providing a global reference to the searchable activity. This is the "glue"
+ * directing the search UI, when invoked from any of your <i>other</i> activities, to use your
+ * application as the default search context.  This is also described in more detail in the 
  * <a href="#SearchabilityMetadata">Searchability Metadata</a> section.</li> 
- * <li>Finally, you may want to define your search results activity as with the 
+ * <li>Finally, you may want to define your search results activity as single-top with the 
  * {@link android.R.attr#launchMode singleTop} launchMode flag.  This allows the system 
  * to launch searches from/to the same activity without creating a pile of them on the 
  * activity stack.  If you do this, be sure to also override 
@@ -255,25 +233,10 @@
  *     doSearchWithQuery(queryString);
  * }</pre>
  * 
- * <a name="FilterSearchApplications"></a>
- * <h3>Filter-Search Applications</h3>
- * 
- * <p>Filter-search applications are those that use live text entry (e.g. keystrokes)) to
- * display and continuously update a list of results.  Primary examples include applications
- * that use locally-stored data.
- * 
- * <p>Filter search is not directly supported by the Search Manager.  Most filter search
- * implementations will use variants of {@link android.widget.Filterable}, such as a 
- * {@link android.widget.ListView} bound to a {@link android.widget.SimpleCursorAdapter}.  However,
- * you may find it useful to mix them together, by declaring your filtered view searchable.  With
- * this configuration, you can still present the standard search dialog in all activities
- * within your application, but transition to a filtered search when you enter the activity
- * and display the results.
- * 
  * <a name="Suggestions"></a>
  * <h3>Search Suggestions</h3>
  * 
- * <p>A powerful feature of the Search Manager is the ability of any application to easily provide
+ * <p>A powerful feature of the search system is the ability of any application to easily provide
  * live "suggestions" in order to prompt the user.  Each application implements suggestions in a 
  * different, unique, and appropriate way.  Suggestions be drawn from many sources, including but 
  * not limited to:
@@ -285,11 +248,11 @@
  * <li>Summaries of possible results</li>
  * </ul>
  * 
- * <p>Another feature of suggestions is that they can expose queries or results before the user
- * ever visits the application.  This reduces the amount of context switching required, and helps
- * the user access their data quickly and with less context shifting.  In order to provide this
- * capability, suggestions are accessed via a 
- * {@link android.content.ContentProvider Content Provider}.  
+ * <p>Once an application is configured to provide search suggestions, those same suggestions can
+ * easily be made available to the system-wide Quick Search Box, providing faster access to its
+ * content from on central prominent place. See
+ * <a href="#ExposingSearchSuggestionsToQuickSearchBox">Exposing Search Suggestions to Quick Search
+ * Box</a> for more details.
  * 
  * <p>The primary form of suggestions is known as <i>queried suggestions</i> and is based on query
  * text that the user has already typed.  This would generally be based on partial matches in
@@ -299,7 +262,8 @@
  * available, they should be weighted based on other factors - for example, most recent queries 
  * or most recent results.
  * 
- * <p><b>Overview of how suggestions are provided.</b>  When the search manager identifies a 
+ * <p><b>Overview of how suggestions are provided.</b>  Suggestions are accessed via a
+ * {@link android.content.ContentProvider Content Provider}. When the search manager identifies a 
  * particular activity as searchable, it will check for certain metadata which indicates that
  * there is also a source of suggestions.  If suggestions are provided, the following steps are
  * taken.
@@ -569,6 +533,11 @@
  * query text is provided and the SUGGEST_COLUMN_INTENT_DATA values are not suitable for user 
  * inspection and editing.</li></ul>
  *
+ * <a name="ExposingSearchSuggestionsToQuickSearchBox"></a>
+ * <h3>Exposing Search Suggestions to Quick Search Box</h3>
+ * 
+ * <p>
+ * 
  * <a name="ActionKeys"></a>
  * <h3>Action Keys</h3>
  * 
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 405db83..78b6cf1 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.app;
 
 import android.content.Context;
@@ -12,6 +28,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.view.ViewRoot;
 
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -21,6 +38,14 @@
     private static String TAG = "WallpaperManager";
     private static boolean DEBUG = false;
 
+    /**
+     * Launch an activity for the user to pick the current global live
+     * wallpaper.
+     * @hide
+     */
+    public static final String ACTION_LIVE_WALLPAPER_CHOOSER
+            = "android.service.wallpaper.LIVE_WALLPAPER_CHOOSER";
+    
     private final Context mContext;
     
     static class Globals extends IWallpaperManagerCallback.Stub {
@@ -88,13 +113,26 @@
     }
 
     /**
-     * Like {@link #peek}, but always returns a valid Drawable.  If
+     * Retrieve a WallpaperManager associated with the given Context.
+     */
+    public static WallpaperManager getInstance(Context context) {
+        return (WallpaperManager)context.getSystemService(
+                Context.WALLPAPER_SERVICE);
+    }
+    
+    /** @hide */
+    public IWallpaperManager getIWallpaperManager() {
+        return getGlobals().mService;
+    }
+    
+    /**
+     * Like {@link #peekDrawable}, but always returns a valid Drawable.  If
      * no wallpaper is set, the system default wallpaper is returned.
      *
      * @return Returns a Drawable object that will draw the wallpaper.
      */
-    public Drawable get() {
-        Drawable dr = peek();
+    public Drawable getDrawable() {
+        Drawable dr = peekDrawable();
         return dr != null ? dr : Resources.getSystem().getDrawable(
                 com.android.internal.R.drawable.default_wallpaper);
     }
@@ -108,7 +146,7 @@
      * @return Returns a Drawable object that will draw the wallpaper or a
      * null pointer if these is none.
      */
-    public Drawable peek() {
+    public Drawable peekDrawable() {
         return getGlobals().peekWallpaper(mContext);
     }
 
@@ -123,7 +161,7 @@
      * @throws IOException If an error occurs reverting to the default
      * wallpaper.
      */
-    public void set(int resid) throws IOException {
+    public void setResource(int resid) throws IOException {
         try {
             Resources resources = mContext.getResources();
             /* Set the wallpaper to the default values */
@@ -154,7 +192,7 @@
      * @throws IOException If an error occurs reverting to the default
      * wallpaper.
      */
-    public void set(Bitmap bitmap) throws IOException {
+    public void setBitmap(Bitmap bitmap) throws IOException {
         try {
             ParcelFileDescriptor fd = getGlobals().mService.setWallpaper(null);
             if (fd == null) {
@@ -185,7 +223,7 @@
      * @throws IOException If an error occurs reverting to the default
      * wallpaper.
      */
-    public void set(InputStream data) throws IOException {
+    public void setStream(InputStream data) throws IOException {
         try {
             ParcelFileDescriptor fd = getGlobals().mService.setWallpaper(null);
             if (fd == null) {
@@ -215,8 +253,8 @@
 
     /**
      * Returns the desired minimum width for the wallpaper. Callers of
-     * {@link #set(android.graphics.Bitmap)} or
-     * {@link #set(java.io.InputStream)} should check this value
+     * {@link #setBitmap(android.graphics.Bitmap)} or
+     * {@link #setStream(java.io.InputStream)} should check this value
      * beforehand to make sure the supplied wallpaper respects the desired
      * minimum width.
      *
@@ -238,8 +276,8 @@
 
     /**
      * Returns the desired minimum height for the wallpaper. Callers of
-     * {@link #set(android.graphics.Bitmap)} or
-     * {@link #set(java.io.InputStream)} should check this value
+     * {@link #setBitmap(android.graphics.Bitmap)} or
+     * {@link #setStream(java.io.InputStream)} should check this value
      * beforehand to make sure the supplied wallpaper respects the desired
      * minimum height.
      *
@@ -267,7 +305,7 @@
      * @param minimumWidth Desired minimum width
      * @param minimumHeight Desired minimum height
      */
-    public void setDimensionHints(int minimumWidth, int minimumHeight) {
+    public void suggestDesiredDimensions(int minimumWidth, int minimumHeight) {
         try {
             getGlobals().mService.setDimensionHints(minimumWidth, minimumHeight);
         } catch (RemoteException e) {
@@ -275,6 +313,28 @@
     }
     
     /**
+     * Set the position of the current wallpaper within any larger space, when
+     * that wallpaper is visible behind the given window.  The X and Y offsets
+     * are floating point numbers ranging from 0 to 1, representing where the
+     * wallpaper should be positioned within the screen space.  These only
+     * make sense when the wallpaper is larger than the screen.
+     * 
+     * @param windowToken The window who these offsets should be associated
+     * with, as returned by {@link android.view.View#getWindowVisibility()
+     * View.getWindowToken()}.
+     * @param xOffset The offset olong the X dimension, from 0 to 1.
+     * @param yOffset The offset along the Y dimension, from 0 to 1.
+     */
+    public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
+        try {
+            ViewRoot.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+                    windowToken, xOffset, yOffset);
+        } catch (RemoteException e) {
+            // Ignore.
+        }
+    }
+    
+    /**
      * Remove any currently set wallpaper, reverting to the system's default
      * wallpaper. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
      * is broadcast.
@@ -283,6 +343,6 @@
      * wallpaper.
      */
     public void clear() throws IOException {
-        set(com.android.internal.R.drawable.default_wallpaper);
+        setResource(com.android.internal.R.drawable.default_wallpaper);
     }
 }
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 9799ac4..cced338 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -24,16 +24,17 @@
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.os.SystemClock;
+import android.os.Parcelable;
+import android.os.Parcel;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.SparseArray;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.RemoteViews;
 import android.widget.TextView;
-import android.widget.FrameLayout.LayoutParams;
 
 /**
  * Provides the glue to show AppWidget views. This class offers automatic animation
@@ -108,6 +109,24 @@
         return mInfo;
     }
 
+    @Override
+    protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
+        final ParcelableSparseArray jail = new ParcelableSparseArray();
+        super.dispatchSaveInstanceState(jail);
+        container.put(generateId(), jail);
+    }
+
+    private int generateId() {
+        final int id = getId();
+        return id == View.NO_ID ? mAppWidgetId : id;
+    }
+
+    @Override
+    protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
+        final ParcelableSparseArray jail = (ParcelableSparseArray) container.get(generateId());
+        super.dispatchRestoreInstanceState(jail);
+    }
+
     /** {@inheritDoc} */
     @Override
     public LayoutParams generateLayoutParams(AttributeSet attrs) {
@@ -339,4 +358,36 @@
         tv.setBackgroundColor(Color.argb(127, 0, 0, 0));
         return tv;
     }
+
+    private static class ParcelableSparseArray extends SparseArray<Parcelable> implements Parcelable {
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel dest, int flags) {
+            final int count = size();
+            dest.writeInt(count);
+            for (int i = 0; i < count; i++) {
+                dest.writeInt(keyAt(i));
+                dest.writeParcelable(valueAt(i), 0);
+            }
+        }
+
+        public static final Parcelable.Creator<ParcelableSparseArray> CREATOR =
+                new Parcelable.Creator<ParcelableSparseArray>() {
+                    public ParcelableSparseArray createFromParcel(Parcel source) {
+                        final ParcelableSparseArray array = new ParcelableSparseArray();
+                        final ClassLoader loader = array.getClass().getClassLoader();
+                        final int count = source.readInt();
+                        for (int i = 0; i < count; i++) {
+                            array.put(source.readInt(), source.readParcelable(loader));
+                        }
+                        return array;
+                    }
+
+                    public ParcelableSparseArray[] newArray(int size) {
+                        return new ParcelableSparseArray[size];
+                    }
+                };
+    }
 }
diff --git a/core/java/android/backup/IRestoreSession.aidl b/core/java/android/backup/IRestoreSession.aidl
index 2a1fbc1..fd40d98 100644
--- a/core/java/android/backup/IRestoreSession.aidl
+++ b/core/java/android/backup/IRestoreSession.aidl
@@ -40,6 +40,8 @@
      * Restore the given set onto the device, replacing the current data of any app
      * contained in the restore set with the data previously backed up.
      *
+     * @return Zero on success; nonzero on error.  The observer will only receive
+     *   progress callbacks if this method returned zero.
      * @param token The token from {@link getAvailableRestoreSets()} corresponding to
      *   the restore set that should be used.
      * @param observer If non-null, this binder points to an object that will receive
@@ -50,6 +52,9 @@
     /**
      * End this restore session.  After this method is called, the IRestoreSession binder
      * is no longer valid.
+     *
+     * <p><b>Note:</b> The caller <i>must</i> invoke this method to end the restore session,
+     *   even if {@link getAvailableRestoreSets} or {@link performRestore} failed.
      */
     void endRestoreSession();
 }
diff --git a/core/java/android/content/AsyncQueryHandler.java b/core/java/android/content/AsyncQueryHandler.java
index ac851cc..c5606ac 100644
--- a/core/java/android/content/AsyncQueryHandler.java
+++ b/core/java/android/content/AsyncQueryHandler.java
@@ -85,6 +85,7 @@
                             cursor.getCount();
                         }
                     } catch (Exception e) {
+                        Log.d(TAG, e.toString());
                         cursor = null;
                     }
 
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index 70ea5d0..f5a4b75 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -16,14 +16,15 @@
 
 package android.content;
 
-import android.net.Uri;
 import android.database.Cursor;
-import android.os.Parcelable;
+import android.net.Uri;
 import android.os.Parcel;
-import android.os.Debug;
+import android.os.Parcelable;
+import android.text.TextUtils;
 
-import java.util.Map;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Map;
 
 public class ContentProviderOperation implements Parcelable {
     /** @hide exposed for unit tests */
@@ -33,7 +34,7 @@
     /** @hide exposed for unit tests */
     public final static int TYPE_DELETE = 3;
     /** @hide exposed for unit tests */
-    public final static int TYPE_COUNT = 4;
+    public final static int TYPE_ASSERT = 4;
 
     private final int mType;
     private final Uri mUri;
@@ -44,8 +45,6 @@
     private final ContentValues mValuesBackReferences;
     private final Map<Integer, Integer> mSelectionArgsBackReferences;
 
-    private static final String[] COUNT_COLUMNS = new String[]{"count(*)"};
-
     /**
      * Creates a {@link ContentProviderOperation} by copying the contents of a
      * {@link Builder}.
@@ -156,15 +155,12 @@
     }
 
     /**
-     * Create a {@link Builder} suitable for building a count query. When used in conjunction
-     * with {@link Builder#withExpectedCount(int)} this is useful for checking that the
-     * uri/selection has the expected number of rows.
-     * {@link ContentProviderOperation}.
-     * @param uri The {@link Uri} to query.
-     * @return a {@link Builder}
+     * Create a {@link Builder} suitable for building a
+     * {@link ContentProviderOperation} to assert a set of values as provided
+     * through {@link Builder#withValues(ContentValues)}.
      */
-    public static Builder newCountQuery(Uri uri) {
-        return new Builder(TYPE_COUNT, uri);
+    public static Builder newAssertQuery(Uri uri) {
+        return new Builder(TYPE_ASSERT, uri);
     }
 
     public Uri getUri() {
@@ -181,7 +177,7 @@
     }
 
     public boolean isReadOperation() {
-        return mType == TYPE_COUNT;
+        return mType == TYPE_ASSERT;
     }
 
     /**
@@ -217,18 +213,30 @@
             numRows = provider.delete(mUri, mSelection, selectionArgs);
         } else if (mType == TYPE_UPDATE) {
             numRows = provider.update(mUri, values, mSelection, selectionArgs);
-        } else if (mType == TYPE_COUNT) {
-            Cursor cursor = provider.query(mUri, COUNT_COLUMNS, mSelection, selectionArgs, null);
+        } else if (mType == TYPE_ASSERT) {
+            // Build projection map from expected values
+            final ArrayList<String> projectionList = new ArrayList<String>();
+            for (Map.Entry<String, Object> entry : values.valueSet()) {
+                projectionList.add(entry.getKey());
+            }
+
+            // Assert that all rows match expected values
+            final String[] projection = projectionList.toArray(new String[projectionList.size()]);
+            final Cursor cursor = provider.query(mUri, projection, mSelection, selectionArgs, null);
+            numRows = cursor.getCount();
             try {
-                if (!cursor.moveToNext()) {
-                    throw new RuntimeException("since we are doing a count query we should always "
-                            + "be able to move to the first row");
+                while (cursor.moveToNext()) {
+                    for (int i = 0; i < projection.length; i++) {
+                        final String cursorValue = cursor.getString(i);
+                        final String expectedValue = values.getAsString(projection[i]);
+                        if (!TextUtils.equals(cursorValue, expectedValue)) {
+                            // Throw exception when expected values don't match
+                            throw new OperationApplicationException("Found value " + cursorValue
+                                    + " when expected " + expectedValue + " for column "
+                                    + projection[i]);
+                        }
+                    }
                 }
-                if (cursor.getCount() != 1) {
-                    throw new RuntimeException("since we are doing a count query there should "
-                            + "always be exacly row, found " + cursor.getCount());
-                }
-                numRows = cursor.getInt(0);
             } finally {
                 cursor.close();
             }
@@ -353,7 +361,7 @@
      * first created by calling {@link ContentProviderOperation#newInsert(android.net.Uri)},
      * {@link ContentProviderOperation#newUpdate(android.net.Uri)},
      * {@link ContentProviderOperation#newDelete(android.net.Uri)} or
-     * {@link ContentProviderOperation#newCountQuery(android.net.Uri)}. The withXXX methods
+     * {@link ContentProviderOperation#newAssertQuery(Uri)}. The withXXX methods
      * can then be used to add parameters to the builder. See the specific methods to find for
      * which {@link Builder} type each is allowed. Call {@link #build} to create the
      * {@link ContentProviderOperation} once all the parameters have been supplied.
@@ -379,7 +387,7 @@
 
         /** Create a ContentProviderOperation from this {@link Builder}. */
         public ContentProviderOperation build() {
-            if (mType == TYPE_UPDATE) {
+            if (mType == TYPE_UPDATE || mType == TYPE_ASSERT) {
                 if ((mValues == null || mValues.size() == 0)
                         && (mValuesBackReferences == null || mValuesBackReferences.size() == 0)) {
                     throw new IllegalArgumentException("Empty values");
@@ -394,13 +402,13 @@
          * value should be used for the column. The value is added as a {@link String}.
          * A column value from the back references takes precedence over a value specified in
          * {@link #withValues}.
-         * This can only be used with builders of type insert or update.
+         * This can only be used with builders of type insert, update, or assert.
          * @return this builder, to allow for chaining.
          */
         public Builder withValueBackReferences(ContentValues backReferences) {
-            if (mType != TYPE_INSERT && mType != TYPE_UPDATE) {
+            if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
                 throw new IllegalArgumentException(
-                        "only inserts and updates can have value back-references");
+                        "only inserts, updates, and asserts can have value back-references");
             }
             mValuesBackReferences = backReferences;
             return this;
@@ -410,13 +418,13 @@
          * Add a ContentValues back reference.
          * A column value from the back references takes precedence over a value specified in
          * {@link #withValues}.
-         * This can only be used with builders of type insert or update.
+         * This can only be used with builders of type insert, update, or assert.
          * @return this builder, to allow for chaining.
          */
         public Builder withValueBackReference(String key, int previousResult) {
-            if (mType != TYPE_INSERT && mType != TYPE_UPDATE) {
+            if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
                 throw new IllegalArgumentException(
-                        "only inserts and updates can have value back-references");
+                        "only inserts, updates, and asserts can have value back-references");
             }
             if (mValuesBackReferences == null) {
                 mValuesBackReferences = new ContentValues();
@@ -428,13 +436,13 @@
         /**
          * Add a back references as a selection arg. Any value at that index of the selection arg
          * that was specified by {@link #withSelection} will be overwritten.
-         * This can only be used with builders of type update, delete, or count query.
+         * This can only be used with builders of type update, delete, or assert.
          * @return this builder, to allow for chaining.
          */
         public Builder withSelectionBackReference(int selectionArgIndex, int previousResult) {
-            if (mType != TYPE_COUNT && mType != TYPE_UPDATE && mType != TYPE_DELETE) {
-                throw new IllegalArgumentException(
-                        "only deletes, updates and counts can have selection back-references");
+            if (mType != TYPE_UPDATE && mType != TYPE_DELETE && mType != TYPE_ASSERT) {
+                throw new IllegalArgumentException("only updates, deletes, and asserts "
+                        + "can have selection back-references");
             }
             if (mSelectionArgsBackReferences == null) {
                 mSelectionArgsBackReferences = new HashMap<Integer, Integer>();
@@ -447,12 +455,13 @@
          * The ContentValues to use. This may be null. These values may be overwritten by
          * the corresponding value specified by {@link #withValueBackReference} or by
          * future calls to {@link #withValues} or {@link #withValue}.
-         * This can only be used with builders of type insert or update.
+         * This can only be used with builders of type insert, update, or assert.
          * @return this builder, to allow for chaining.
          */
         public Builder withValues(ContentValues values) {
-            if (mType != TYPE_INSERT && mType != TYPE_UPDATE) {
-                throw new IllegalArgumentException("only inserts and updates can have values");
+            if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
+                throw new IllegalArgumentException(
+                        "only inserts, updates, and asserts can have values");
             }
             if (mValues == null) {
                 mValues = new ContentValues();
@@ -464,14 +473,14 @@
         /**
          * A value to insert or update. This value may be overwritten by
          * the corresponding value specified by {@link #withValueBackReference}.
-         * This can only be used with builders of type insert or update.
+         * This can only be used with builders of type insert, update, or assert.
          * @param key the name of this value
          * @param value the value itself. the type must be acceptable for insertion by
          * {@link ContentValues#put}
          * @return this builder, to allow for chaining.
          */
         public Builder withValue(String key, Object value) {
-            if (mType != TYPE_INSERT && mType != TYPE_UPDATE) {
+            if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
                 throw new IllegalArgumentException("only inserts and updates can have values");
             }
             if (mValues == null) {
@@ -508,13 +517,13 @@
          * replaced with the corresponding occurence of the selection argument. Any of the
          * selection arguments may be overwritten by a selection argument back reference as
          * specified by {@link #withSelectionBackReference}.
-         * This can only be used with builders of type update, delete, or count query.
+         * This can only be used with builders of type update, delete, or assert.
          * @return this builder, to allow for chaining.
          */
         public Builder withSelection(String selection, String[] selectionArgs) {
-            if (mType != TYPE_DELETE && mType != TYPE_UPDATE && mType != TYPE_COUNT) {
+            if (mType != TYPE_UPDATE && mType != TYPE_DELETE && mType != TYPE_ASSERT) {
                 throw new IllegalArgumentException(
-                        "only deletes, updates and counts can have selections");
+                        "only updates, deletes, and asserts can have selections");
             }
             mSelection = selection;
             mSelectionArgs = selectionArgs;
@@ -524,13 +533,13 @@
         /**
          * If set then if the number of rows affected by this operation do not match
          * this count {@link OperationApplicationException} will be throw.
-         * This can only be used with builders of type update, delete, or count query.
+         * This can only be used with builders of type update, delete, or assert.
          * @return this builder, to allow for chaining.
          */
         public Builder withExpectedCount(int count) {
-            if (mType != TYPE_DELETE && mType != TYPE_UPDATE && mType != TYPE_COUNT) {
+            if (mType != TYPE_UPDATE && mType != TYPE_DELETE && mType != TYPE_ASSERT) {
                 throw new IllegalArgumentException(
-                        "only deletes, updates and counts can have expected counts");
+                        "only updates, deletes, and asserts can have expected counts");
             }
             mExpectedCount = count;
             return this;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 1105899..dbe6fb0 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -488,13 +488,13 @@
     public abstract String[] databaseList();
 
     /**
-     * @deprecated Use {@link android.app.WallpaperManager#get
+     * @deprecated Use {@link android.app.WallpaperManager#getDrawable
      * WallpaperManager.get()} instead.
      */
     public abstract Drawable getWallpaper();
 
     /**
-     * @deprecated Use {@link android.app.WallpaperManager#peek
+     * @deprecated Use {@link android.app.WallpaperManager#peekDrawable
      * WallpaperManager.peek()} instead.
      */
     public abstract Drawable peekWallpaper();
@@ -512,13 +512,13 @@
     public abstract int getWallpaperDesiredMinimumHeight();
 
     /**
-     * @deprecated Use {@link android.app.WallpaperManager#set(Bitmap)
+     * @deprecated Use {@link android.app.WallpaperManager#setBitmap(Bitmap)
      * WallpaperManager.set()} instead.
      */
     public abstract void setWallpaper(Bitmap bitmap) throws IOException;
 
     /**
-     * @deprecated Use {@link android.app.WallpaperManager#set(InputStream)
+     * @deprecated Use {@link android.app.WallpaperManager#setStream(InputStream)
      * WallpaperManager.set()} instead.
      */
     public abstract void setWallpaper(InputStream data) throws IOException;
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index dff7cae..9e966cd 100755
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -163,8 +163,8 @@
     private static final int MSG_REPEAT = 3;
     private static final int MSG_LONGPRESS = 4;
 
-    private static final int DELAY_BEFORE_PREVIEW = 40;
-    private static final int DELAY_AFTER_PREVIEW = 60;
+    private static final int DELAY_BEFORE_PREVIEW = 0;
+    private static final int DELAY_AFTER_PREVIEW = 70;
     
     private int mVerticalCorrection;
     private int mProximityThreshold;
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 9b0c70e..f950c4b 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -177,36 +177,6 @@
         public static final String DISPLAY_NAME = "display_name";
 
         /**
-         * Reference to the row in the data table holding the primary phone number.
-         * <P>Type: INTEGER REFERENCES data(_id)</P>
-         */
-        @Deprecated
-        public static final String PRIMARY_PHONE_ID = "primary_phone_id";
-
-        /**
-         * Reference to the row in the data table holding the default phone number.
-         * If the contact has only one phone number, that number is the default one.
-         * Otherwise it is the one explicitly selected by the user as primary.
-         * <P>Type: INTEGER REFERENCES data(_id)</P>
-         */
-        public static final String DEFAULT_PHONE_ID = "default_phone_id";
-
-        /**
-         * Reference to the row in the data table holding the primary email address.
-         * <P>Type: INTEGER REFERENCES data(_id)</P>
-         */
-        @Deprecated
-        public static final String PRIMARY_EMAIL_ID = "primary_email_id";
-
-        /**
-         * Reference to the row in the data table holding the default email address.
-         * If the contact has only one email address, that address is the default one.
-         * Otherwise it is the one explicitly selected by the user as primary.
-         * <P>Type: INTEGER REFERENCES data(_id)</P>
-         */
-        public static final String DEFAULT_EMAIL_ID = "default_email_id";
-
-        /**
          * Reference to the row in the data table holding the photo.
          * <P>Type: INTEGER REFERENCES data(_id)</P>
          */
@@ -225,43 +195,11 @@
         public static final String PRESENCE_STATUS = Presence.PRESENCE_STATUS;
 
         /**
-         * The type of data, for example Home or Work.
+         * An indicator of whether this contact has at least one phone number. "1" if there is
+         * at least one phone number, "0" otherwise.
          * <P>Type: INTEGER</P>
          */
-        @Deprecated
-        public static final String PRIMARY_PHONE_TYPE = CommonDataKinds.Phone.TYPE;
-
-        /**
-         * The type of data, for example Home or Work.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String DEFAULT_PHONE_TYPE = "default_phone_type";
-
-        /**
-         * The user defined label for the primary phone.
-         * <P>Type: TEXT</P>
-         */
-        @Deprecated
-        public static final String PRIMARY_PHONE_LABEL = CommonDataKinds.Phone.LABEL;
-
-        /**
-         * The user defined label for the default phone.
-         * <P>Type: TEXT</P>
-         */
-        public static final String DEFAULT_PHONE_LABEL = "default_phone_label";
-
-        /**
-         * The primary phone number.
-         * <P>Type: TEXT</P>
-         */
-        @Deprecated
-        public static final String PRIMARY_PHONE_NUMBER = CommonDataKinds.Phone.NUMBER;
-
-        /**
-         * The default phone number.
-         * <P>Type: TEXT</P>
-         */
-        public static final String DEFAULT_PHONE_NUMBER = "default_phone_number";
+        public static final String HAS_PHONE_NUMBER = "has_phone_number";
     }
 
     /**
@@ -573,8 +511,8 @@
         public static final String SYNC4 = "data_sync4";
 
         /**
-         * An optional update or insert URI parameter that determines if the
-         * corresponding raw contact should be marked as dirty. The default
+         * An optional insert, update or delete URI parameter that determines if
+         * the corresponding raw contact should be marked as dirty. The default
          * value is true.
          */
         public static final String MARK_AS_DIRTY = "mark_as_dirty";
@@ -1401,6 +1339,17 @@
          * Type: INTEGER
          */
         public static final String GROUP_VISIBLE = "group_visible";
+
+        /**
+         * The "deleted" flag: "0" by default, "1" if the row has been marked
+         * for deletion. When {@link android.content.ContentResolver#delete} is
+         * called on a raw contact, it is marked for deletion and removed from its
+         * aggregate contact. The sync adaptor deletes the raw contact on the server and
+         * then calls ContactResolver.delete once more, this time passing the
+         * {@link RawContacts#DELETE_PERMANENTLY} query parameter to finalize the data removal.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String DELETED = "deleted";
     }
 
     /**
@@ -1434,6 +1383,20 @@
          * The MIME type of a single group.
          */
         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/group";
+
+        /**
+         * Query parameter that can be passed with the {@link #CONTENT_URI} URI
+         * to the {@link android.content.ContentResolver#delete} method to
+         * indicate that the raw contact can be deleted physically, rather than
+         * merely marked as deleted.
+         */
+        public static final String DELETE_PERMANENTLY = "delete_permanently";
+
+        /**
+         * An optional update or insert URI parameter that determines if the
+         * group should be marked as dirty. The default value is true.
+         */
+        public static final String MARK_AS_DIRTY = "mark_as_dirty";
     }
 
     /**
diff --git a/core/java/android/provider/DrmStore.java b/core/java/android/provider/DrmStore.java
index db71854..c438ac4 100644
--- a/core/java/android/provider/DrmStore.java
+++ b/core/java/android/provider/DrmStore.java
@@ -35,7 +35,7 @@
 
 /**
  * The DRM provider contains forward locked DRM content.
- * 
+ *
  * @hide
  */
 public final class DrmStore
@@ -43,13 +43,13 @@
     private static final String TAG = "DrmStore";
 
     public static final String AUTHORITY = "drm";
-    
+
     /**
      * This is in the Manifest class of the drm provider, but that isn't visible
      * in the framework.
      */
     private static final String ACCESS_DRM_PERMISSION = "android.permission.ACCESS_DRM";
-    
+
     /**
      * Fields for DRM database
      */
@@ -82,18 +82,18 @@
     }
 
     public interface Images extends Columns {
-     
+
         public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/images");
     }
-     
+
     public interface Audio extends Columns {
-     
+
         public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/audio");
     }
 
     /**
      * Utility function for inserting a file into the DRM content provider.
-     * 
+     *
      * @param cr The content resolver to use
      * @param file The file to insert
      * @param title The title for the content (or null)
@@ -101,12 +101,46 @@
      */
     public static final Intent addDrmFile(ContentResolver cr, File file, String title) {
         FileInputStream fis = null;
-        OutputStream os = null;
         Intent result = null;
 
         try {
             fis = new FileInputStream(file);
-            DrmRawContent content = new DrmRawContent(fis, (int) file.length(),
+            if (title == null) {
+                title = file.getName();
+                int lastDot = title.lastIndexOf('.');
+                if (lastDot > 0) {
+                    title = title.substring(0, lastDot);
+                }
+            }
+            result = addDrmFile(cr, fis, title);
+        } catch (Exception e) {
+            Log.e(TAG, "pushing file failed", e);
+        } finally {
+            try {
+                if (fis != null)
+                    fis.close();
+            } catch (IOException e) {
+                Log.e(TAG, "IOException in DrmStore.addDrmFile()", e);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Utility function for inserting a file stream into the DRM content provider.
+     *
+     * @param cr The content resolver to use
+     * @param fileStream The FileInputStream to insert
+     * @param title The title for the content (or null)
+     * @return uri to the DRM record or null
+     */
+    public static final Intent addDrmFile(ContentResolver cr, FileInputStream fis, String title) {
+        OutputStream os = null;
+        Intent result = null;
+
+        try {
+            DrmRawContent content = new DrmRawContent(fis, (int) fis.available(),
                     DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING);
             String mimeType = content.getContentType();
 
@@ -126,14 +160,6 @@
 
             if (contentUri != null) {
                 ContentValues values = new ContentValues(3);
-                // compute title from file name, if it is not specified
-                if (title == null) {
-                    title = file.getName();
-                    int lastDot = title.lastIndexOf('.');
-                    if (lastDot > 0) {
-                        title = title.substring(0, lastDot);
-                    }
-                }
                 values.put(DrmStore.Columns.TITLE, title);
                 values.put(DrmStore.Columns.SIZE, size);
                 values.put(DrmStore.Columns.MIME_TYPE, mimeType);
@@ -162,7 +188,7 @@
                 if (os != null)
                     os.close();
             } catch (IOException e) {
-                Log.e(TAG, "IOException in DrmTest.onCreate()", e);
+                Log.e(TAG, "IOException in DrmStore.addDrmFile()", e);
             }
         }
 
@@ -172,7 +198,7 @@
     /**
      * Utility function to enforce any permissions required to access DRM
      * content.
-     * 
+     *
      * @param context A context used for checking calling permission.
      */
     public static void enforceAccessDrmPermission(Context context) {
@@ -181,5 +207,5 @@
             throw new SecurityException("Requires DRM permission");
         }
     }
-     
+
 }
diff --git a/core/java/android/provider/Gmail.java b/core/java/android/provider/Gmail.java
index c4b29ae..5702e7c 100644
--- a/core/java/android/provider/Gmail.java
+++ b/core/java/android/provider/Gmail.java
@@ -83,7 +83,7 @@
     public static final String LABEL_OUTBOX = "^^out";
 
     public static final String AUTHORITY = "gmail-ls";
-    private static final String TAG = "gmail-ls";
+    private static final String TAG = "Gmail";
     private static final String AUTHORITY_PLUS_CONVERSATIONS =
             "content://" + AUTHORITY + "/conversations/";
     private static final String AUTHORITY_PLUS_LABELS =
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3e818eb..e1b8e99 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2728,7 +2728,14 @@
          * Controls how many attempts Gmail will try to upload an uphill operations before it
          * abandons the operation. Defaults to 20.
          */
-        public static final String GMAIL_NUM_RETRY_UPHILL_OP = "gmail_discard_error_uphill_op";
+        public static final String GMAIL_NUM_RETRY_UPHILL_OP = "gmail_num_retry_uphill_op";
+
+        /**
+         * How much time in seconds Gmail will try to upload an uphill operations before it
+         * abandons the operation. Defaults to 36400 (one day).
+         */
+        public static final String GMAIL_WAIT_TIME_RETRY_UPHILL_OP =
+                "gmail_wait_time_retry_uphill_op";
 
         /**
          * Controls if the protocol buffer version of the protocol will use a multipart request for
@@ -2940,6 +2947,11 @@
         public static final String DATA_MESSAGE_GET_APP_TOKEN_URL =
                 "data_messaging_get_app_token_url";
 
+	/**
+	 * Use android://&lt;it&gt; routing infos for Google Sync Server subcriptions.
+	 */
+	public static final String GSYNC_USE_RMQ2_ROUTING_INFO = "gsync_use_rmq2_routing_info";
+
         /**
          * Enable use of ssl session caching.
          * 'db' - save each session in a (per process) database
@@ -3346,6 +3358,14 @@
         public static final String USE_LOCATION_FOR_SERVICES = "use_location";
 
         /**
+         * The length of the calendar sync window into the future.
+         * This specifies the number of days into the future for the sliding window sync.
+         * Setting this to zero will disable sliding sync.
+         */
+        public static final String GOOGLE_CALENDAR_SYNC_WINDOW_DAYS =
+                "google_calendar_sync_window_days";
+
+        /**
          * @deprecated
          * @hide
          */
diff --git a/core/java/android/service/wallpaper/IWallpaperConnection.aidl b/core/java/android/service/wallpaper/IWallpaperConnection.aidl
new file mode 100644
index 0000000..b09ccab
--- /dev/null
+++ b/core/java/android/service/wallpaper/IWallpaperConnection.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.wallpaper;
+
+import android.os.ParcelFileDescriptor;
+import android.service.wallpaper.IWallpaperEngine;
+
+/**
+ * @hide
+ */
+interface IWallpaperConnection {
+	void attachEngine(IWallpaperEngine engine);
+    ParcelFileDescriptor setWallpaper(String name);
+}
diff --git a/core/java/android/service/wallpaper/IWallpaperEngine.aidl b/core/java/android/service/wallpaper/IWallpaperEngine.aidl
new file mode 100644
index 0000000..9586e34
--- /dev/null
+++ b/core/java/android/service/wallpaper/IWallpaperEngine.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.wallpaper;
+
+/**
+ * @hide
+ */
+oneway interface IWallpaperEngine {
+	void destroy();
+}
diff --git a/core/java/android/service/wallpaper/IWallpaperService.aidl b/core/java/android/service/wallpaper/IWallpaperService.aidl
index 97e032b..eb58c3b 100644
--- a/core/java/android/service/wallpaper/IWallpaperService.aidl
+++ b/core/java/android/service/wallpaper/IWallpaperService.aidl
@@ -16,9 +16,12 @@
 
 package android.service.wallpaper;
 
+import android.service.wallpaper.IWallpaperConnection;
+
 /**
  * @hide
  */
 oneway interface IWallpaperService {
-    void onInterrupt();
+    void attach(IWallpaperConnection connection,
+    		IBinder windowToken, int reqWidth, int reqHeight);
 }
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index a729ed5..7017514 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -17,17 +17,30 @@
 package android.service.wallpaper;
 
 import com.android.internal.os.HandlerCaller;
+import com.android.internal.view.BaseIWindow;
+import com.android.internal.view.BaseSurfaceHolder;
 
 import android.app.Service;
+import android.app.WallpaperManager;
 import android.content.Intent;
+import android.graphics.Rect;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.Gravity;
+import android.view.IWindowSession;
+import android.view.SurfaceHolder;
+import android.view.View;
+import android.view.ViewRoot;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
 
 /**
  * A wallpaper service is responsible for showing a live wallpaper behind
  * applications that would like to sit on top of it.
+ * @hide Live Wallpaper
  */
 public abstract class WallpaperService extends Service {
     /**
@@ -36,8 +49,377 @@
     public static final String SERVICE_INTERFACE =
         "android.service.wallpaper.WallpaperService";
 
-    private static final String LOG_TAG = "WallpaperService";
+    static final String TAG = "WallpaperService";
+    static final boolean DEBUG = true;
+    
+    private static final int DO_ATTACH = 10;
+    private static final int DO_DETACH = 20;
+    
+    private static final int MSG_UPDATE_SURFACE = 10000;
+    private static final int MSG_VISIBILITY_CHANGED = 10010;
+    
+    /**
+     * The actual implementation of a wallpaper.  A wallpaper service may
+     * have multiple instances running (for example as a real wallpaper
+     * and as a preview), each of which is represented by its own Engine
+     * instance.  You must implement {@link WallpaperService#onCreateEngine()}
+     * to return your concrete Engine implementation.
+     */
+    public class Engine {
+        IWallpaperEngineWrapper mIWallpaperEngine;
+        
+        // Copies from mIWallpaperEngine.
+        HandlerCaller mCaller;
+        IWallpaperConnection mConnection;
+        IBinder mWindowToken;
+        
+        boolean mInitializing = true;
+        
+        // Current window state.
+        boolean mCreated;
+        boolean mIsCreating;
+        boolean mDrawingAllowed;
+        int mWidth;
+        int mHeight;
+        int mFormat;
+        int mType;
+        boolean mDestroyReportNeeded;
+        final Rect mVisibleInsets = new Rect();
+        final Rect mWinFrame = new Rect();
+        final Rect mContentInsets = new Rect();
+        
+        final WindowManager.LayoutParams mLayout
+                = new WindowManager.LayoutParams();
+        IWindowSession mSession;
 
+        final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() {
+
+            @Override
+            public boolean onAllowLockCanvas() {
+                return mDrawingAllowed;
+            }
+
+            @Override
+            public void onRelayoutContainer() {
+                Message msg = mCaller.obtainMessage(MSG_UPDATE_SURFACE);
+                mCaller.sendMessage(msg);
+            }
+
+            @Override
+            public void onUpdateSurface() {
+                Message msg = mCaller.obtainMessage(MSG_UPDATE_SURFACE);
+                mCaller.sendMessage(msg);
+            }
+
+            public boolean isCreating() {
+                return mIsCreating;
+            }
+
+            public void setKeepScreenOn(boolean screenOn) {
+                // Ignore.
+            }
+            
+        };
+        
+        final BaseIWindow mWindow = new BaseIWindow() {
+            public void dispatchAppVisibility(boolean visible) {
+                Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED,
+                        visible ? 1 : 0);
+                mCaller.sendMessage(msg);
+            }
+        };
+        
+        /**
+         * Provides access to the surface in which this wallpaper is drawn.
+         */
+        public SurfaceHolder getSurfaceHolder() {
+            return mSurfaceHolder;
+        }
+        
+        /**
+         * Convenience for {@link WallpaperManager#getDesiredMinimumWidth()
+         * WallpaperManager.getDesiredMinimumWidth()}, returning the width
+         * that the system would like this wallpaper to run in.
+         */
+        public int getDesiredMinimumWidth() {
+            return mIWallpaperEngine.mReqWidth;
+        }
+        
+        /**
+         * Convenience for {@link WallpaperManager#getDesiredMinimumHeight()
+         * WallpaperManager.getDesiredMinimumHeight()}, returning the height
+         * that the system would like this wallpaper to run in.
+         */
+        public int getDesiredMinimumHeight() {
+            return mIWallpaperEngine.mReqHeight;
+        }
+        
+        /**
+         * Called once to initialize the engine.  After returning, the
+         * engine's surface will be created by the framework.
+         */
+        public void onCreate(SurfaceHolder surfaceHolder) {
+        }
+        
+        /**
+         * Called right before the engine is going away.  After this the
+         * surface will be destroyed and this Engine object is no longer
+         * valid.
+         */
+        public void onDestroy() {
+        }
+        
+        /**
+         * Called to inform you of the wallpaper becoming visible or
+         * hidden.  <em>It is very important that a wallpaper only use
+         * CPU while it is visible.</em>.
+         */
+        public void onVisibilityChanged(boolean visible) {
+        }
+        
+        /**
+         * Convenience for {@link SurfaceHolder.Callback#surfaceChanged
+         * SurfaceHolder.Callback.surfaceChanged()}.
+         */
+        public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+        }
+
+        /**
+         * Convenience for {@link SurfaceHolder.Callback#surfaceCreated
+         * SurfaceHolder.Callback.surfaceCreated()}.
+         */
+        public void onSurfaceCreated(SurfaceHolder holder) {
+        }
+
+        /**
+         * Convenience for {@link SurfaceHolder.Callback#surfaceDestroyed
+         * SurfaceHolder.Callback.surfaceDestroyed()}.
+         */
+        public void onSurfaceDestroyed(SurfaceHolder holder) {
+        }
+
+        void updateSurface(boolean force) {
+            int myWidth = mSurfaceHolder.getRequestedWidth();
+            if (myWidth <= 0) myWidth = mIWallpaperEngine.mReqWidth;
+            int myHeight = mSurfaceHolder.getRequestedHeight();
+            if (myHeight <= 0) myHeight = mIWallpaperEngine.mReqHeight;
+            
+            final boolean creating = !mCreated;
+            final boolean formatChanged = mFormat != mSurfaceHolder.getRequestedFormat();
+            final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
+            final boolean typeChanged = mType != mSurfaceHolder.getRequestedType();
+            if (force || creating || formatChanged || sizeChanged || typeChanged) {
+
+                if (DEBUG) Log.i(TAG, "Changes: creating=" + creating
+                        + " format=" + formatChanged + " size=" + sizeChanged);
+
+                try {
+                    mWidth = myWidth;
+                    mHeight = myHeight;
+                    mFormat = mSurfaceHolder.getRequestedFormat();
+                    mType = mSurfaceHolder.getRequestedType();
+
+                    // Scaling/Translate window's layout here because mLayout is not used elsewhere.
+                    
+                    // Places the window relative
+                    mLayout.x = 0;
+                    mLayout.y = 0;
+                    mLayout.width = myWidth;
+                    mLayout.height = myHeight;
+                    
+                    mLayout.format = mFormat;
+                    mLayout.flags |=WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                                  | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                                  | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                                  | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+                                  ;
+
+                    mLayout.memoryType = mType;
+                    mLayout.token = mWindowToken;
+
+                    if (!mCreated) {
+                        mLayout.type = WindowManager.LayoutParams.TYPE_WALLPAPER;
+                        mLayout.gravity = Gravity.LEFT|Gravity.TOP;
+                        mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets);
+                    }
+                    
+                    mSurfaceHolder.mSurfaceLock.lock();
+                    mDrawingAllowed = true;
+
+                    final int relayoutResult = mSession.relayout(
+                        mWindow, mLayout, mWidth, mHeight,
+                            View.VISIBLE, false, mWinFrame, mContentInsets,
+                            mVisibleInsets, mSurfaceHolder.mSurface);
+
+                    if (DEBUG) Log.i(TAG, "New surface: " + mSurfaceHolder.mSurface
+                            + ", frame=" + mWinFrame);
+                    
+                    mSurfaceHolder.mSurfaceLock.unlock();
+
+                    try {
+                        mDestroyReportNeeded = true;
+
+                        SurfaceHolder.Callback callbacks[] = null;
+                        synchronized (mSurfaceHolder.mCallbacks) {
+                            final int N = mSurfaceHolder.mCallbacks.size();
+                            if (N > 0) {
+                                callbacks = new SurfaceHolder.Callback[N];
+                                mSurfaceHolder.mCallbacks.toArray(callbacks);
+                            }
+                        }
+
+                        if (!mCreated) {
+                            mIsCreating = true;
+                            onSurfaceCreated(mSurfaceHolder);
+                            if (callbacks != null) {
+                                for (SurfaceHolder.Callback c : callbacks) {
+                                    c.surfaceCreated(mSurfaceHolder);
+                                }
+                            }
+                        }
+                        if (creating || formatChanged || sizeChanged) {
+                            onSurfaceChanged(mSurfaceHolder, mFormat, mWidth, mHeight);
+                            if (callbacks != null) {
+                                for (SurfaceHolder.Callback c : callbacks) {
+                                    c.surfaceChanged(mSurfaceHolder, mFormat, mWidth, mHeight);
+                                }
+                            }
+                        }
+                    } finally {
+                        mIsCreating = false;
+                        mCreated = true;
+                        if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
+                            mSession.finishDrawing(mWindow);
+                        }
+                    }
+                } catch (RemoteException ex) {
+                }
+                if (DEBUG) Log.v(
+                    TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
+                    " w=" + mLayout.width + " h=" + mLayout.height);
+            }
+        }
+        
+        void attach(IWallpaperEngineWrapper wrapper) {
+            mIWallpaperEngine = wrapper;
+            mCaller = wrapper.mCaller;
+            mConnection = wrapper.mConnection;
+            mWindowToken = wrapper.mWindowToken;
+            mSurfaceHolder.setSizeFromLayout();
+            mInitializing = true;
+            mSession = ViewRoot.getWindowSession(getMainLooper());
+            mWindow.setSession(mSession);
+            
+            onCreate(mSurfaceHolder);
+            
+            mInitializing = false;
+            updateSurface(false);
+        }
+        
+        void detach() {
+            onDestroy();
+            if (mDestroyReportNeeded) {
+                mDestroyReportNeeded = false;
+                SurfaceHolder.Callback callbacks[];
+                synchronized (mSurfaceHolder.mCallbacks) {
+                    callbacks = new SurfaceHolder.Callback[
+                            mSurfaceHolder.mCallbacks.size()];
+                    mSurfaceHolder.mCallbacks.toArray(callbacks);
+                }
+                for (SurfaceHolder.Callback c : callbacks) {
+                    c.surfaceDestroyed(mSurfaceHolder);
+                }
+            }
+            if (mCreated) {
+                try {
+                    mSession.remove(mWindow);
+                } catch (RemoteException e) {
+                }
+                mSurfaceHolder.mSurface.clear();
+                mCreated = false;
+            }
+        }
+    }
+    
+    class IWallpaperEngineWrapper extends IWallpaperEngine.Stub
+            implements HandlerCaller.Callback {
+        private final HandlerCaller mCaller;
+
+        final IWallpaperConnection mConnection;
+        final IBinder mWindowToken;
+        int mReqWidth;
+        int mReqHeight;
+        
+        Engine mEngine;
+        
+        IWallpaperEngineWrapper(WallpaperService context,
+                IWallpaperConnection conn, IBinder windowToken,
+                int reqWidth, int reqHeight) {
+            mCaller = new HandlerCaller(context, this);
+            mConnection = conn;
+            mWindowToken = windowToken;
+            mReqWidth = reqWidth;
+            mReqHeight = reqHeight;
+            
+            try {
+                conn.attachEngine(this);
+            } catch (RemoteException e) {
+                destroy();
+            }
+            
+            Message msg = mCaller.obtainMessage(DO_ATTACH);
+            mCaller.sendMessage(msg);
+        }
+        
+        public void destroy() {
+            Message msg = mCaller.obtainMessage(DO_DETACH);
+            mCaller.sendMessage(msg);
+        }
+
+        public void executeMessage(Message message) {
+            switch (message.what) {
+                case DO_ATTACH: {
+                    Engine engine = onCreateEngine();
+                    mEngine = engine;
+                    engine.attach(this);
+                    return;
+                }
+                case DO_DETACH: {
+                    mEngine.detach();
+                    return;
+                }
+                case MSG_UPDATE_SURFACE:
+                    mEngine.updateSurface(false);
+                    break;
+                case MSG_VISIBILITY_CHANGED:
+                    if (DEBUG) Log.v(TAG, "Visibility change in " + mEngine
+                            + ": " + message.arg1);
+                    mEngine.onVisibilityChanged(message.arg1 != 0);
+                    break;
+                default :
+                    Log.w(TAG, "Unknown message type " + message.what);
+            }
+        }
+    }
+
+    /**
+     * Implements the internal {@link IWallpaperService} interface to convert
+     * incoming calls to it back to calls on an {@link WallpaperService}.
+     */
+    class IWallpaperServiceWrapper extends IWallpaperService.Stub {
+        private final WallpaperService mTarget;
+
+        public IWallpaperServiceWrapper(WallpaperService context) {
+            mTarget = context;
+        }
+
+        public void attach(IWallpaperConnection conn,
+                IBinder windowToken, int reqWidth, int reqHeight) {
+            new IWallpaperEngineWrapper(
+                    mTarget, conn, windowToken, reqWidth, reqHeight);
+        }
+    }
+    
     /**
      * Implement to return the implementation of the internal accessibility
      * service interface.  Subclasses should not override.
@@ -46,38 +428,6 @@
     public final IBinder onBind(Intent intent) {
         return new IWallpaperServiceWrapper(this);
     }
-
-    /**
-     * Implements the internal {@link IWallpaperService} interface to convert
-     * incoming calls to it back to calls on an {@link WallpaperService}.
-     */
-    class IWallpaperServiceWrapper extends IWallpaperService.Stub
-            implements HandlerCaller.Callback {
-
-        private static final int DO_ON_INTERRUPT = 10;
-        
-        private final HandlerCaller mCaller;
-
-        private WallpaperService mTarget;
-
-        public IWallpaperServiceWrapper(WallpaperService context) {
-            mTarget = context;
-            mCaller = new HandlerCaller(context, this);
-        }
-
-        public void onInterrupt() {
-            Message message = mCaller.obtainMessage(DO_ON_INTERRUPT);
-            mCaller.sendMessage(message);
-        }
-
-        public void executeMessage(Message message) {
-            switch (message.what) {
-                case DO_ON_INTERRUPT :
-                    //mTarget.onInterrupt();
-                    return;
-                default :
-                    Log.w(LOG_TAG, "Unknown message type " + message.what);
-            }
-        }
-    }
+    
+    public abstract Engine onCreateEngine();
 }
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index b033c6a..04a0ec8 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -189,6 +189,12 @@
                 "android.speech.tts.engine.INSTALL_TTS_DATA";
 
         /**
+         * {@hide}
+         */
+        @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+        public static final String ACTION_TTS_DATA_INSTALLED =
+                "android.speech.tts.engine.TTS_DATA_INSTALLED";
+        /**
          * Broadcast Action: Starts the activity from the platform Text-To-Speech
          * engine to verify the proper installation and availability of the
          * resource files on the system. Upon completion, the activity will
@@ -233,6 +239,16 @@
          */
         public static final String EXTRA_VOICE_DATA_FILES_INFO = "dataFilesInfo";
 
+        // extras for a TTS engine's data installation
+        /**
+         * Extra information received with the {@link #ACTION_TTS_DATA_INSTALLED} intent
+         * which indicates whether the TTS data installation requested with
+         * {@link #ACTION_INSTALL_TTS_DATA} completed successfully or not. The value is
+         * {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
+         * {@hide}
+         */
+        public static final String EXTRA_TTS_DATA_INSTALLED = "dataInstalled";
+
         // keys for the parameters passed with speak commands. Hidden keys are used internally
         // to maintain engine state for each TextToSpeech instance.
         /**
diff --git a/core/java/android/util/MathUtils.java b/core/java/android/util/MathUtils.java
index d8509a0..c80d90f 100644
--- a/core/java/android/util/MathUtils.java
+++ b/core/java/android/util/MathUtils.java
@@ -116,7 +116,7 @@
         return degrees * DEG_TO_RAD;
     }
 
-    public static float degress(float radians) {
+    public static float degrees(float radians) {
         return radians * RAD_TO_DEG;
     }
 
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 5607d4b..3e6cdc2 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -90,7 +90,6 @@
     void exitKeyguardSecurely(IOnKeyguardExitResult callback);
     boolean inKeyguardRestrictedInputMode();
 
-    
     // These can only be called with the SET_ANIMATON_SCALE permission.
     float getAnimationScale(int which);
     float[] getAnimationScales();
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 1156856..4d662d2 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -108,4 +108,10 @@
     boolean getInTouchMode();
     
     boolean performHapticFeedback(IWindow window, int effectId, boolean always);
+    
+    /**
+     * For windows with the wallpaper behind them, and the wallpaper is
+     * larger than the screen, set the offset within the screen.
+     */
+    void setWallpaperPosition(IBinder windowToken, float x, float y);
 }
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 0d44b4e..216fc5e 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -192,6 +192,22 @@
 
     private final int mDensity;
 
+    public static IWindowSession getWindowSession(Looper mainLooper) {
+        synchronized (mStaticInit) {
+            if (!mInitialized) {
+                try {
+                    InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
+                    sWindowSession = IWindowManager.Stub.asInterface(
+                            ServiceManager.getService("window"))
+                            .openSession(imm.getClient(), imm.getInputContext());
+                    mInitialized = true;
+                } catch (RemoteException e) {
+                }
+            }
+            return sWindowSession;
+        }
+    }
+    
     public ViewRoot(Context context) {
         super();
 
@@ -204,19 +220,8 @@
         // Initialize the statics when this class is first instantiated. This is
         // done here instead of in the static block because Zygote does not
         // allow the spawning of threads.
-        synchronized (mStaticInit) {
-            if (!mInitialized) {
-                try {
-                    InputMethodManager imm = InputMethodManager.getInstance(context);
-                    sWindowSession = IWindowManager.Stub.asInterface(
-                            ServiceManager.getService("window"))
-                            .openSession(imm.getClient(), imm.getInputContext());
-                    mInitialized = true;
-                } catch (RemoteException e) {
-                }
-            }
-        }
-
+        getWindowSession(context.getMainLooper());
+        
         mThread = Thread.currentThread();
         mLocation = new WindowLeaked(null);
         mLocation.fillInStackTrace();
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c0be9e8..35d7cc9 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -314,6 +314,12 @@
         public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12;
 
         /**
+         * Window type: wallpaper window, placed behind any window that wants
+         * to sit on top of the wallpaper.
+         */
+        public static final int TYPE_WALLPAPER          = FIRST_SYSTEM_WINDOW+13;
+
+        /**
          * End of types of system windows.
          */
         public static final int LAST_SYSTEM_WINDOW      = 2999;
@@ -479,16 +485,23 @@
          * key guard or any other lock screens. Can be used with
          * {@link #FLAG_KEEP_SCREEN_ON} to turn screen on and display windows
          * directly before showing the key guard window
-         *
-         * {@hide} */
+         */
         public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;
 
+        /** Window flag: ask that the system wallpaper be shown behind
+         * your window.  The window surface must be translucent to be able
+         * to actually see the wallpaper behind it; this flag just ensures
+         * that the wallpaper surface will be there if this window actually
+         * has translucent regions.
+         */
+        public static final int FLAG_SHOW_WALLPAPER = 0x00100000;
+        
         /** Window flag: special flag to limit the size of the window to be
          * original size ([320x480] x density). Used to create window for applications
          * running under compatibility mode.
          *
          * {@hide} */
-        public static final int FLAG_COMPATIBLE_WINDOW = 0x00100000;
+        public static final int FLAG_COMPATIBLE_WINDOW = 0x20000000;
 
         /** Window flag: a special option intended for system dialogs.  When
          * this flag is set, the window will demand focus unconditionally when
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index d797890..e30687f 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -446,13 +446,22 @@
      * @hide
      */
     static public InputMethodManager getInstance(Context context) {
+        return getInstance(context.getMainLooper());
+    }
+    
+    /**
+     * Internally, the input method manager can't be context-dependent, so
+     * we have this here for the places that need it.
+     * @hide
+     */
+    static public InputMethodManager getInstance(Looper mainLooper) {
         synchronized (mInstanceSync) {
             if (mInstance != null) {
                 return mInstance;
             }
             IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
             IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
-            mInstance = new InputMethodManager(service, context.getMainLooper());
+            mInstance = new InputMethodManager(service, mainLooper);
         }
         return mInstance;
     }
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 2ac77ac..afa2c35 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -685,7 +685,7 @@
 
             default:
                 Log.e(LOGTAG, "getRawResFilename got incompatible resource ID");
-                return new String();
+                return "";
         }
         TypedValue value = new TypedValue();
         mContext.getResources().getValue(resid, value, true);
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index 7b32a26..d8f87cf 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -429,7 +429,7 @@
         if (checkCacheRedirect(cacheRet.httpStatusCode)) {
             // location is in database, no need to keep the file
             cacheRet.contentLength = 0;
-            cacheRet.localPath = new String();
+            cacheRet.localPath = "";
             cacheRet.outFile.delete();
         } else if (cacheRet.contentLength == 0) {
             cacheRet.outFile.delete();
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index b2277cb..96bf46e 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -111,7 +111,7 @@
 
     // Result transportation object for returning results across thread
     // boundaries.
-    private class ResultTransport<E> {
+    private static class ResultTransport<E> {
         // Private result object
         private E mResult;
 
diff --git a/core/java/android/webkit/DateSorter.java b/core/java/android/webkit/DateSorter.java
index 750403b..c46702e 100644
--- a/core/java/android/webkit/DateSorter.java
+++ b/core/java/android/webkit/DateSorter.java
@@ -43,9 +43,6 @@
     
     private static final int NUM_DAYS_AGO = 5;
 
-    Date mDate = new Date();
-    Calendar mCal = Calendar.getInstance();
-
     /**
      * @param context Application context
      */
diff --git a/core/java/android/webkit/GeolocationService.java b/core/java/android/webkit/GeolocationService.java
new file mode 100755
index 0000000..78b25ba
--- /dev/null
+++ b/core/java/android/webkit/GeolocationService.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.app.ActivityThread;
+import android.content.Context;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.location.LocationProvider;
+import android.os.Bundle;
+import android.util.Log;
+import android.webkit.WebView;
+import android.webkit.WebViewCore;
+
+
+/**
+ * Implements the Java side of GeolocationServiceAndroid.
+ * @hide Pending API council review.
+ */
+public final class GeolocationService implements LocationListener {
+
+    // Log tag
+    private static final String TAG = "geolocationService";
+
+    private long mNativeObject;
+    private LocationManager mLocationManager;
+    private boolean mIsGpsEnabled;
+    private boolean mIsRunning;
+    private boolean mIsNetworkProviderAvailable;
+    private boolean mIsGpsProviderAvailable;
+
+    /**
+     * Constructor
+     * @param nativeObject The native object to which this object will report position updates and
+     *     errors.
+     */
+    public GeolocationService(long nativeObject) {
+        mNativeObject = nativeObject;
+        // Register newLocationAvailable with platform service.
+        ActivityThread thread = ActivityThread.systemMain();
+        Context context = thread.getApplication();
+        mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+        if (mLocationManager == null) {
+            Log.e(TAG, "Could not get location manager.");
+        }
+     }
+
+    /**
+     * Start listening for location updates.
+     */
+    public void start() {
+        registerForLocationUpdates();
+        mIsRunning = true;
+    }
+
+    /**
+     * Stop listening for location updates.
+     */
+    public void stop() {
+        unregisterFromLocationUpdates();
+        mIsRunning = false;
+    }
+
+    /**
+     * Sets whether to use the GPS.
+     * @param enable Whether to use the GPS.
+     */
+    public void setEnableGps(boolean enable) {
+        if (mIsGpsEnabled != enable) {
+            mIsGpsEnabled = enable;
+            if (mIsRunning) {
+                // There's no way to unregister from a single provider, so we can
+                // only unregister from all, then reregister with all but the GPS.
+                unregisterFromLocationUpdates();
+                registerForLocationUpdates();
+            }
+        }
+    }
+
+    /**
+     * LocationListener implementation.
+     * Called when the location has changed.
+     * @param location The new location, as a Location object.
+     */
+    public void onLocationChanged(Location location) {
+        // Callbacks from the system location sevice are queued to this thread, so it's possible
+        // that we receive callbacks after unregistering. At this point, the native object will no
+        // longer exist.
+        if (mIsRunning) {
+            nativeNewLocationAvailable(mNativeObject, location);
+        }
+    }
+
+    /**
+     * LocationListener implementation.
+     * Called when the provider status changes.
+     * @param provider The name of the provider.
+     * @param status The new status of the provider.
+     * @param extras an optional Bundle with provider specific data.
+     */
+    public void onStatusChanged(String providerName, int status, Bundle extras) {
+        boolean isAvailable = (status == LocationProvider.AVAILABLE);
+        if (LocationManager.NETWORK_PROVIDER.equals(providerName)) {
+            mIsNetworkProviderAvailable = isAvailable;
+        } else if (LocationManager.GPS_PROVIDER.equals(providerName)) {
+            mIsGpsProviderAvailable = isAvailable;
+        }
+        maybeReportError("The last location provider is no longer available");
+    }
+
+    /**
+     * LocationListener implementation.
+     * Called when the provider is enabled.
+     * @param provider The name of the location provider that is now enabled.
+     */
+    public void onProviderEnabled(String providerName) {
+        // No need to notify the native side. It's enough to start sending
+        // valid position fixes again.
+        if (LocationManager.NETWORK_PROVIDER.equals(providerName)) {
+            mIsNetworkProviderAvailable = true;
+        } else if (LocationManager.GPS_PROVIDER.equals(providerName)) {
+            mIsGpsProviderAvailable = true;
+        }
+    }
+
+    /**
+     * LocationListener implementation.
+     * Called when the provider is disabled.
+     * @param provider The name of the location provider that is now disabled.
+     */
+    public void onProviderDisabled(String providerName) {
+        if (LocationManager.NETWORK_PROVIDER.equals(providerName)) {
+            mIsNetworkProviderAvailable = false;
+        } else if (LocationManager.GPS_PROVIDER.equals(providerName)) {
+            mIsGpsProviderAvailable = false;
+        }
+        maybeReportError("The last location provider was disabled");
+    }
+
+    /**
+     * Registers this object with the location service.
+     */
+    private void registerForLocationUpdates() {
+        mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
+        mIsNetworkProviderAvailable = true;
+        if (mIsGpsEnabled) {
+            mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
+            mIsGpsProviderAvailable = true;
+        }
+    }
+
+    /**
+     * Unregisters this object from the location service.
+     */
+    private void unregisterFromLocationUpdates() {
+        mLocationManager.removeUpdates(this);
+    }
+
+    /**
+     * Reports an error if neither the network nor the GPS provider is available.
+     */
+    private void maybeReportError(String message) {
+        // Callbacks from the system location sevice are queued to this thread, so it's possible
+        // that we receive callbacks after unregistering. At this point, the native object will no
+        // longer exist.
+        if (mIsRunning && !mIsNetworkProviderAvailable && !mIsGpsProviderAvailable) {
+            nativeNewErrorAvailable(mNativeObject, message);
+        }
+    }
+
+    // Native functions
+    private static native void nativeNewLocationAvailable(long nativeObject, Location location);
+    private static native void nativeNewErrorAvailable(long nativeObject, String message);
+}
diff --git a/core/java/android/webkit/HttpAuthHandler.java b/core/java/android/webkit/HttpAuthHandler.java
index 84dc9f0..1c17575 100644
--- a/core/java/android/webkit/HttpAuthHandler.java
+++ b/core/java/android/webkit/HttpAuthHandler.java
@@ -49,8 +49,8 @@
 
 
     // Message id for handling the user response
-    private final int AUTH_PROCEED = 100;
-    private final int AUTH_CANCEL = 200;
+    private static final int AUTH_PROCEED = 100;
+    private static final int AUTH_CANCEL = 200;
 
     /**
      * Creates a new HTTP authentication handler with an empty
diff --git a/core/java/android/webkit/Network.java b/core/java/android/webkit/Network.java
index fb60109..0b9e596 100644
--- a/core/java/android/webkit/Network.java
+++ b/core/java/android/webkit/Network.java
@@ -136,7 +136,7 @@
             Assert.assertTrue(Thread.currentThread().
                     getName().equals(WebViewCore.THREAD_NAME));
         }
-        mSslErrorHandler = new SslErrorHandler(this);
+        mSslErrorHandler = new SslErrorHandler();
         mHttpAuthHandler = new HttpAuthHandler(this);
 
         mRequestQueue = new RequestQueue(context);
diff --git a/core/java/android/webkit/PluginData.java b/core/java/android/webkit/PluginData.java
index 2b539fe..02be1f7 100644
--- a/core/java/android/webkit/PluginData.java
+++ b/core/java/android/webkit/PluginData.java
@@ -47,10 +47,6 @@
     private Map<String, String[]> mHeaders;
 
     /**
-     * The index of the header value in the above mapping.
-     */
-    private int mHeaderValueIndex;
-    /**
      * The associated HTTP response code.
      */
     private int mStatusCode;
diff --git a/core/java/android/webkit/SslErrorHandler.java b/core/java/android/webkit/SslErrorHandler.java
index cc1e750..5011244 100644
--- a/core/java/android/webkit/SslErrorHandler.java
+++ b/core/java/android/webkit/SslErrorHandler.java
@@ -42,11 +42,6 @@
     private static final String LOGTAG = "network";
 
     /**
-     * Network.
-     */
-    private Network mNetwork;
-
-    /**
      * Queue of loaders that experience SSL-related problems.
      */
     private LinkedList<LoadListener> mLoaderQueue;
@@ -57,7 +52,7 @@
     private Bundle mSslPrefTable;
 
     // Message id for handling the response
-    private final int HANDLE_RESPONSE = 100;
+    private static final int HANDLE_RESPONSE = 100;
 
     @Override
     public void handleMessage(Message msg) {
@@ -72,9 +67,7 @@
     /**
      * Creates a new error handler with an empty loader queue.
      */
-    /* package */ SslErrorHandler(Network network) {
-        mNetwork = network;
-
+    /* package */ SslErrorHandler() {
         mLoaderQueue = new LinkedList<LoadListener>();
         mSslPrefTable = new Bundle();
     }
diff --git a/core/java/android/webkit/WebIconDatabase.java b/core/java/android/webkit/WebIconDatabase.java
index d284f5e..6cc6bb4 100644
--- a/core/java/android/webkit/WebIconDatabase.java
+++ b/core/java/android/webkit/WebIconDatabase.java
@@ -37,7 +37,7 @@
     private final EventHandler mEventHandler = new EventHandler();
 
     // Class to handle messages before WebCore is ready
-    private class EventHandler extends Handler {
+    private static class EventHandler extends Handler {
         // Message ids
         static final int OPEN         = 0;
         static final int CLOSE        = 1;
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index c3b359e..ae560fb 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -70,7 +70,7 @@
 
     private Handler mHandler = null;
 
-    private class Origin {
+    private static class Origin {
         String mOrigin = null;
         long mQuota = 0;
 
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 2d87dd2..cc7a228 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1276,8 +1276,6 @@
      *
      * @param url The url of the resource to load.
      * @param postData The data will be passed to "POST" request.
-     *
-     * @hide pending API solidification
      */
     public void postUrl(String url, byte[] postData) {
         if (URLUtil.isNetworkUrl(url)) {
@@ -2516,7 +2514,11 @@
 
     @Override
     protected void finalize() throws Throwable {
-        destroy();
+        try {
+            destroy();
+        } finally {
+            super.finalize();
+        }
     }
 
     @Override
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 86b0843..05464b5 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -1999,10 +1999,11 @@
         private int mPointer;
         private final boolean mIsFixedSize;
         SurfaceViewProxy(Context context, ViewManager.ChildView childView,
-                int pointer, boolean isFixedSize) {
+                int pointer, int pixelFormat, boolean isFixedSize) {
             super(context);
             setWillNotDraw(false); // this prevents the black box artifact
             getHolder().addCallback(this);
+            getHolder().setFormat(pixelFormat);
             mChildView = childView;
             mChildView.mView = this;
             mPointer = pointer;
@@ -2041,12 +2042,13 @@
 
     // PluginWidget functions for mainting SurfaceViews for the Surface drawing
     // model.
-    private SurfaceView createSurface(int nativePointer, boolean isFixedSize) {
+    private SurfaceView createSurface(int nativePointer, int pixelFormat,
+                                      boolean isFixedSize) {
         if (mWebView == null) {
             return null;
         }
-        return new SurfaceViewProxy(mContext,
-                mWebView.mViewManager.createView(), nativePointer, isFixedSize);
+        return new SurfaceViewProxy(mContext, mWebView.mViewManager.createView(),
+                                    nativePointer, pixelFormat, isFixedSize);
     }
 
     private void destroySurface(SurfaceView surface) {
diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java
index 932555d..2ab9e09 100644
--- a/core/java/com/android/internal/os/HandlerCaller.java
+++ b/core/java/com/android/internal/os/HandlerCaller.java
@@ -132,6 +132,14 @@
         return mH.obtainMessage(what, arg1, arg2, arg3);
     }
     
+    public Message obtainMessageIIOO(int what, int arg1, int arg2,
+            Object arg3, Object arg4) {
+        SomeArgs args = obtainArgs();
+        args.arg1 = arg3;
+        args.arg2 = arg4;
+        return mH.obtainMessage(what, arg1, arg2, args);
+    }
+    
     public Message obtainMessageIOO(int what, int arg1, Object arg2, Object arg3) {
         SomeArgs args = obtainArgs();
         args.arg1 = arg2;
diff --git a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
new file mode 100644
index 0000000..6d50840
--- /dev/null
+++ b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.service.wallpaper;
+
+import android.app.WallpaperManager;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.service.wallpaper.WallpaperService;
+import android.view.SurfaceHolder;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.content.Intent;
+import android.content.BroadcastReceiver;
+
+/**
+ * Default built-in wallpaper that simply shows a static image.
+ */
+public class ImageWallpaper extends WallpaperService {
+    WallpaperManager mWallpaperManager;
+    ImageWallpaper.DrawableEngine mEngine;
+    private WallpaperObserver mReceiver;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
+        IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
+        mReceiver = new WallpaperObserver();
+        registerReceiver(mReceiver, filter);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        unregisterReceiver(mReceiver);
+    }
+
+    public Engine onCreateEngine() {
+        mEngine = new DrawableEngine();
+        return mEngine;
+    }
+
+    class WallpaperObserver extends BroadcastReceiver {
+        public void onReceive(Context context, Intent intent) {
+            mEngine.updateWallpaper();
+        }
+    }
+
+    class DrawableEngine extends Engine {
+        private final Object mLock = new Object();
+        Drawable mBackground;
+
+        @Override
+        public void onCreate(SurfaceHolder surfaceHolder) {
+            super.onCreate(surfaceHolder);
+            mBackground = mWallpaperManager.getDrawable();
+        }
+
+        @Override
+        public void onVisibilityChanged(boolean visible) {
+            drawFrame();
+        }
+        
+        @Override
+        public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+            super.onSurfaceChanged(holder, format, width, height);
+            drawFrame();
+        }
+
+        @Override
+        public void onSurfaceCreated(SurfaceHolder holder) {
+            super.onSurfaceCreated(holder);
+        }
+
+        @Override
+        public void onSurfaceDestroyed(SurfaceHolder holder) {
+            super.onSurfaceDestroyed(holder);
+        }
+        
+        void drawFrame() {
+            SurfaceHolder sh = getSurfaceHolder();
+            Canvas c = null;
+            try {
+                c = sh.lockCanvas();
+                if (c != null) {
+                    final Rect frame = sh.getSurfaceFrame();
+                    synchronized (mLock) {
+                        final Drawable background = mBackground;
+                        background.setBounds(frame);
+                        background.draw(c);
+                    }
+                }
+            } finally {
+                if (c != null) sh.unlockCanvasAndPost(c);
+            }
+        }
+
+        void updateWallpaper() {
+            synchronized (mLock) {
+                mBackground = mWallpaperManager.getDrawable();
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
new file mode 100644
index 0000000..7449067
--- /dev/null
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -0,0 +1,68 @@
+package com.android.internal.view;
+
+import android.graphics.Rect;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.view.IWindow;
+import android.view.IWindowSession;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+public class BaseIWindow extends IWindow.Stub {
+    private IWindowSession mSession;
+    
+    public void setSession(IWindowSession session) {
+        mSession = session;
+    }
+    
+    public void resized(int w, int h, Rect coveredInsets,
+            Rect visibleInsets, boolean reportDraw) {
+        if (reportDraw) {
+            try {
+                mSession.finishDrawing(this);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    public void dispatchKey(KeyEvent event) {
+        try {
+            mSession.finishKey(this);
+        } catch (RemoteException ex) {
+        }
+    }
+
+    public void dispatchPointer(MotionEvent event, long eventTime) {
+        try {
+            if (event == null) {
+                event = mSession.getPendingPointerMove(this);
+            } else if (event.getAction() != MotionEvent.ACTION_OUTSIDE) {
+                mSession.finishKey(this);
+            }
+        } catch (RemoteException ex) {
+        }
+    }
+
+    public void dispatchTrackball(MotionEvent event, long eventTime) {
+        try {
+            if (event == null) {
+                event = mSession.getPendingTrackballMove(this);
+            } else if (event.getAction() != MotionEvent.ACTION_OUTSIDE) {
+                mSession.finishKey(this);
+            }
+        } catch (RemoteException ex) {
+        }
+    }
+
+    public void dispatchAppVisibility(boolean visible) {
+    }
+
+    public void dispatchGetNewSurface() {
+    }
+
+    public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
+    }
+
+    public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
+    }
+}
diff --git a/core/java/com/android/internal/view/BaseSurfaceHolder.java b/core/java/com/android/internal/view/BaseSurfaceHolder.java
new file mode 100644
index 0000000..2364ae4
--- /dev/null
+++ b/core/java/com/android/internal/view/BaseSurfaceHolder.java
@@ -0,0 +1,169 @@
+package com.android.internal.view;
+
+import android.graphics.Canvas;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+
+import java.util.ArrayList;
+import java.util.concurrent.locks.ReentrantLock;
+
+public abstract class BaseSurfaceHolder implements SurfaceHolder {
+    private static final String TAG = "BaseSurfaceHolder";
+    static final boolean DEBUG = false;
+
+    public final ArrayList<SurfaceHolder.Callback> mCallbacks
+            = new ArrayList<SurfaceHolder.Callback>();
+
+    public final ReentrantLock mSurfaceLock = new ReentrantLock();
+    public final Surface mSurface = new Surface();
+
+    int mRequestedWidth = -1;
+    int mRequestedHeight = -1;
+    int mRequestedFormat = PixelFormat.OPAQUE;
+    int mRequestedType = -1;
+
+    long mLastLockTime = 0;
+    
+    int mType = -1;
+    final Rect mSurfaceFrame = new Rect();
+    
+    public abstract void onUpdateSurface();
+    public abstract void onRelayoutContainer();
+    public abstract boolean onAllowLockCanvas();
+    
+    public int getRequestedWidth() {
+        return mRequestedWidth;
+    }
+    
+    public int getRequestedHeight() {
+        return mRequestedHeight;
+    }
+    
+    public int getRequestedFormat() {
+        return mRequestedFormat;
+    }
+    
+    public int getRequestedType() {
+        return mRequestedType;
+    }
+    
+    public void addCallback(Callback callback) {
+        synchronized (mCallbacks) {
+            // This is a linear search, but in practice we'll 
+            // have only a couple callbacks, so it doesn't matter.
+            if (mCallbacks.contains(callback) == false) {      
+                mCallbacks.add(callback);
+            }
+        }
+    }
+
+    public void removeCallback(Callback callback) {
+        synchronized (mCallbacks) {
+            mCallbacks.remove(callback);
+        }
+    }
+    
+    public void setFixedSize(int width, int height) {
+        if (mRequestedWidth != width || mRequestedHeight != height) {
+            mRequestedWidth = width;
+            mRequestedHeight = height;
+            onRelayoutContainer();
+        }
+    }
+
+    public void setSizeFromLayout() {
+        if (mRequestedWidth != -1 || mRequestedHeight != -1) {
+            mRequestedWidth = mRequestedHeight = -1;
+            onRelayoutContainer();
+        }
+    }
+
+    public void setFormat(int format) {
+        if (mRequestedFormat != format) {
+            mRequestedFormat = format;
+            onUpdateSurface();
+        }
+    }
+
+    public void setType(int type) {
+        switch (type) {
+        case SURFACE_TYPE_NORMAL:
+        case SURFACE_TYPE_HARDWARE:
+        case SURFACE_TYPE_GPU:
+        case SURFACE_TYPE_PUSH_BUFFERS:
+            if (mRequestedType != type) {
+                mRequestedType = type;
+                onUpdateSurface();
+            }
+            break;
+        }
+    }
+
+    public Canvas lockCanvas() {
+        return internalLockCanvas(null);
+    }
+
+    public Canvas lockCanvas(Rect dirty) {
+        return internalLockCanvas(dirty);
+    }
+
+    private final Canvas internalLockCanvas(Rect dirty) {
+        if (mType == SURFACE_TYPE_PUSH_BUFFERS) {
+            throw new BadSurfaceTypeException(
+                    "Surface type is SURFACE_TYPE_PUSH_BUFFERS");
+        }
+        mSurfaceLock.lock();
+
+        if (DEBUG) Log.i(TAG, "Locking canvas..,");
+
+        Canvas c = null;
+        if (onAllowLockCanvas()) {
+            Rect frame = dirty != null ? dirty : mSurfaceFrame;
+            try {
+                c = mSurface.lockCanvas(frame);
+            } catch (Exception e) {
+                Log.e(TAG, "Exception locking surface", e);
+            }
+        }
+
+        if (DEBUG) Log.i(TAG, "Returned canvas: " + c);
+        if (c != null) {
+            mLastLockTime = SystemClock.uptimeMillis();
+            return c;
+        }
+        
+        // If the Surface is not ready to be drawn, then return null,
+        // but throttle calls to this function so it isn't called more
+        // than every 100ms.
+        long now = SystemClock.uptimeMillis();
+        long nextTime = mLastLockTime + 100;
+        if (nextTime > now) {
+            try {
+                Thread.sleep(nextTime-now);
+            } catch (InterruptedException e) {
+            }
+            now = SystemClock.uptimeMillis();
+        }
+        mLastLockTime = now;
+        mSurfaceLock.unlock();
+        
+        return null;
+    }
+
+    public void unlockCanvasAndPost(Canvas canvas) {
+        mSurface.unlockCanvasAndPost(canvas);
+        mSurfaceLock.unlock();
+    }
+
+    public Surface getSurface() {
+        return mSurface;
+    }
+
+    public Rect getSurfaceFrame() {
+        return mSurfaceFrame;
+    }
+};
diff --git a/core/java/com/android/internal/widget/ContactHeaderWidget.java b/core/java/com/android/internal/widget/ContactHeaderWidget.java
index 45bd0cf..eac5d2d 100644
--- a/core/java/com/android/internal/widget/ContactHeaderWidget.java
+++ b/core/java/com/android/internal/widget/ContactHeaderWidget.java
@@ -52,7 +52,8 @@
 
 
 /* Widget that is used across system apps for displaying a header banner with contact info */
-public class ContactHeaderWidget extends FrameLayout implements View.OnClickListener {
+public class ContactHeaderWidget extends FrameLayout implements View.OnClickListener,
+        View.OnLongClickListener {
 
     private static final String TAG = "ContactHeaderWidget";
 
@@ -71,6 +72,13 @@
 
     protected ContentResolver mContentResolver;
 
+    public interface ContactHeaderListener {
+        public void onPhotoLongClick(View view);
+        public void onDisplayNameLongClick(View view);
+    }
+
+    private ContactHeaderListener mListener;
+
     //Projection used for the summary info in the header.
     protected static final String[] HEADER_PROJECTION = new String[] {
         Contacts.DISPLAY_NAME,
@@ -125,6 +133,8 @@
         inflater.inflate(R.layout.contact_header, this);
 
         mDisplayNameView = (TextView) findViewById(R.id.name);
+        mDisplayNameView.setOnLongClickListener(this);
+
         mPhoneticNameView = (TextView) findViewById(R.id.phonetic_name);
 
         mStarredView = (CheckBox)findViewById(R.id.star);
@@ -132,6 +142,7 @@
 
         mPhotoView = (ImageView)findViewById(R.id.photo);
         mPhotoView.setOnClickListener(this);
+        mPhotoView.setOnLongClickListener(this);
 
         mStatusView = (TextView)findViewById(R.id.status);
 
@@ -152,6 +163,35 @@
         mQueryHandler = new QueryHandler(mContentResolver);
     }
 
+    public void setContactHeaderListener(ContactHeaderListener listener) {
+        mListener = listener;
+    }
+
+    /** {@inheritDoc} */
+    public boolean onLongClick(View v) {
+        switch (v.getId()) {
+            case R.id.photo:
+                performPhotoLongClick();
+                return true;
+            case R.id.name:
+                performDisplayNameLongClick();
+                return true;
+        }
+        return false;
+    }
+
+    private void performPhotoLongClick() {
+        if (mListener != null) {
+            mListener.onPhotoLongClick(mPhotoView);
+        }
+    }
+
+    private void performDisplayNameLongClick() {
+        if (mListener != null) {
+            mListener.onDisplayNameLongClick(mDisplayNameView);
+        }
+    }
+
     private class QueryHandler extends AsyncQueryHandler {
 
         public QueryHandler(ContentResolver cr) {
@@ -233,6 +273,8 @@
             if (c.moveToFirst()) {
                 long contactId = c.getLong(EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX);
                 bindFromContactId(contactId);
+            } else {
+                bindStatic(emailAddress, "");
             }
         } finally {
             if (c != null) {
@@ -257,6 +299,8 @@
             if (c.moveToFirst()) {
                 long contactId = c.getLong(PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX);
                 bindFromContactId(contactId);
+            } else {
+                bindStatic(number, "");
             }
         } finally {
             if (c != null) {
@@ -265,6 +309,13 @@
         }
     }
 
+    public void bindStatic(String main, String secondary) {
+        mDisplayNameView.setText(main);
+        mStatusView.setText(secondary);
+        mStarredView.setVisibility(View.GONE);
+        mPhotoView.setImageBitmap(loadPlaceholderPhoto(null));
+    }
+
     protected void redrawHeader() {
         if (mContactDataUri != null) {
             mQueryHandler.startQuery(TOKEN_CONTACT_INFO, null, mContactDataUri, HEADER_PROJECTION,
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index bd3c805..02677f4 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -242,11 +242,12 @@
 
 static inline SkBitmap::Config convertPixelFormat(PixelFormat format)
 {
-    /* note: if PIXEL_FORMAT_XRGB_8888 means that all alpha bytes are 0xFF, then
+    /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then
         we can map to SkBitmap::kARGB_8888_Config, and optionally call
         bitmap.setIsOpaque(true) on the resulting SkBitmap (as an accelerator)
     */
 	switch (format) {
+	case PIXEL_FORMAT_RGBX_8888:    return SkBitmap::kARGB_8888_Config;
     case PIXEL_FORMAT_RGBA_8888:    return SkBitmap::kARGB_8888_Config;
     case PIXEL_FORMAT_RGBA_4444:    return SkBitmap::kARGB_4444_Config;
 	case PIXEL_FORMAT_RGB_565:		return SkBitmap::kRGB_565_Config;
@@ -294,6 +295,9 @@
     SkBitmap bitmap;
     ssize_t bpr = info.s * bytesPerPixel(info.format);
     bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, bpr);
+    if (info.format == PIXEL_FORMAT_RGBX_8888) {
+        bitmap.setIsOpaque(true);
+    }
     if (info.w > 0 && info.h > 0) {
         bitmap.setPixels(info.bits);
     } else {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 69ef96c..cf85af5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -894,6 +894,13 @@
         android:description="@string/permdesc_bindInputMethod"
         android:protectionLevel="signature" />
 
+    <!-- Must be required by wallpaper services, to ensure that only the
+         system can bind to them. -->
+    <permission android:name="android.permission.BIND_WALLPAPER"
+        android:label="@string/permlab_bindWallpaper"
+        android:description="@string/permdesc_bindWallpaper"
+        android:protectionLevel="signature" />
+
     <!-- Allows low-level access to setting the orientation (actually
          rotation) of the screen.  Not for use by normal applications. -->
     <permission android:name="android.permission.SET_ORIENTATION"
@@ -1082,6 +1089,12 @@
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
         android:protectionLevel="signature" />
 
+    <!-- Allows applications to set a live wallpaper.
+         @hide -->
+    <permission android:name="android.permission.SET_WALLPAPER_COMPONENT"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="signature" />
+
     <application android:process="system"
                  android:persistent="true"
                  android:hasCode="false"
@@ -1140,7 +1153,14 @@
         </activity>
 
         <service android:name="com.android.server.LoadAverageService"
-            android:exported="true" />
+                android:exported="true" />
+
+        <service android:name="com.android.internal.service.wallpaper.ImageWallpaper"
+                android:permission="android.permission.BIND_WALLPAPER">
+            <intent-filter>
+                <action android:name="android.service.wallpaper.WallpaperService" />
+            </intent-filter>
+        </service>
 
         <receiver android:name="com.android.server.BootReceiver" >
             <intent-filter>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index ad6d94f..01253d3 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -215,6 +215,9 @@
         <attr name="windowIsFloating" format="boolean" />
         <!-- Flag indicating whether this is a translucent window. -->
         <attr name="windowIsTranslucent" format="boolean" />
+        <!-- Flag indicating that this window's background should be the
+        	 user's current wallpaper. -->
+        <attr name="windowShowWallpaper" format="boolean" />
         <!-- This Drawable is overlaid over the foreground of the Window's content area, usually
              to place a shadow below the title.  -->
         <attr name="windowContentOverlay" format="reference" />
@@ -900,6 +903,7 @@
         <attr name="windowFullscreen" />
         <attr name="windowIsFloating" />
         <attr name="windowIsTranslucent" />
+        <attr name="windowShowWallpaper" />
         <attr name="windowAnimationStyle" />
         <attr name="windowSoftInputMode" />
         <attr name="windowDisablePreview" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index f8dd4c1..ef87b17 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1167,9 +1167,13 @@
 
   <public type="attr" name="accountType" />
   <public type="attr" name="contentAuthority" />
+  <public type="attr" name="windowShowWallpaper" />
 
   <public type="drawable" name="stat_sys_vp_phone_call" />
   <public type="drawable" name="stat_sys_vp_phone_call_on_hold" />
   
+  <public type="style" name="Theme.Wallpaper" />
+  <public type="style" name="Theme.Wallpaper.NoTitleBar" />
+  <public type="style" name="Theme.Wallpaper.NoTitleBar.Fullscreen" />
 
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 558d91e..68f2070 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -599,6 +599,12 @@
         interface of an input method. Should never be needed for normal applications.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_bindWallpaper">bind to a wallpaper</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_bindWallpaper">Allows the holder to bind to the top-level
+        interface of a wallpaper. Should never be needed for normal applications.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_setOrientation">change screen orientation</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_setOrientation">Allows an application to change
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index e3fffb7..1e3a4a8 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -280,6 +280,25 @@
         <item name="android:windowContentOverlay">@null</item>
     </style>
     
+    <!-- Default theme for windows that want to have the user's selected
+    	 wallpaper appear behind them.  -->
+    <style name="Theme.Wallpaper">
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:windowShowWallpaper">true</item>
+    </style>
+
+    <!-- Variant of the translucent theme with no title bar -->
+    <style name="Theme.Wallpaper.NoTitleBar">
+        <item name="android:windowNoTitle">true</item>
+    </style>
+
+    <!-- Variant of the translucent theme that has no title bar and
+         fills the entire screen -->
+    <style name="Theme.Wallpaper.NoTitleBar.Fullscreen">
+        <item name="android:windowFullscreen">true</item>
+        <item name="android:windowContentOverlay">@null</item>
+    </style>
+
     <!-- Default theme for translucent activities, that is windows that allow you
          to see through them to the windows behind.  This sets up the translucent
          flag and appropriate animations for your windows.  -->
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index dc80cf5..6b50406 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -237,7 +237,7 @@
             final int N = mDrawableContainerState.getChildCount();
             final Drawable[] drawables = mDrawableContainerState.getChildren();
             for (int i = 0; i < N; i++) {
-                drawables[i].mutate();
+                if (drawables[i] != null) drawables[i].mutate();
             }
             mMutated = true;
         }
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 3b6571a..ca35a40 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -43,8 +43,11 @@
     }
 
     public void destroy() {
+        if(mDestroyed) {
+            throw new IllegalStateException("Object already destroyed.");
+        }
+        mDestroyed = true;
         mRS.nAllocationDestroy(mID);
-        mID = 0;
     }
 
     public void data(int[] d) {
@@ -71,6 +74,15 @@
         mRS.nAllocationSubData2D(mID, xoff, yoff, w, h, d);
     }
 
+    public void readData(int[] d) {
+        mRS.nAllocationRead(mID, d);
+    }
+
+    public void readData(float[] d) {
+        mRS.nAllocationRead(mID, d);
+    }
+
+
     public class Adapter1D extends BaseObj {
         Adapter1D(int id, RenderScript rs) {
             super(rs);
@@ -160,17 +172,27 @@
         mBitmapOptions.inScaled = false;
     }
 
-    static public Allocation createTyped(RenderScript rs, Type type) {
+    static public Allocation createTyped(RenderScript rs, Type type)
+        throws IllegalArgumentException {
+
+        if(type.mID == 0) {
+            throw new IllegalStateException("Bad Type");
+        }
         int id = rs.nAllocationCreateTyped(type.mID);
         return new Allocation(id, rs);
     }
 
-    static public Allocation createSized(RenderScript rs, Element e, int count) {
+    static public Allocation createSized(RenderScript rs, Element e, int count)
+        throws IllegalArgumentException {
+
         int id;
         if(e.mIsPredefined) {
             id = rs.nAllocationCreatePredefSized(e.mPredefinedID, count);
         } else {
             id = rs.nAllocationCreateSized(e.mID, count);
+            if(id == 0) {
+                throw new IllegalStateException("Bad element.");
+            }
         }
         return new Allocation(id, rs);
     }
diff --git a/graphics/java/android/renderscript/BaseObj.java b/graphics/java/android/renderscript/BaseObj.java
index f70aee5..f760035 100644
--- a/graphics/java/android/renderscript/BaseObj.java
+++ b/graphics/java/android/renderscript/BaseObj.java
@@ -27,6 +27,7 @@
     BaseObj(RenderScript rs) {
         mRS = rs;
         mID = 0;
+        mDestroyed = false;
     }
 
     public int getID() {
@@ -34,6 +35,7 @@
     }
 
     int mID;
+    boolean mDestroyed;
     String mName;
     RenderScript mRS;
 
@@ -57,7 +59,7 @@
 
     protected void finalize() throws Throwable
     {
-        if (mID != 0) {
+        if (!mDestroyed) {
             Log.v(RenderScript.LOG_TAG,
                   "Element finalized without having released the RS reference.");
         }
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index 409d267..14d9115 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -137,8 +137,11 @@
         if(mIsPredefined) {
             throw new IllegalStateException("Attempting to destroy a predefined Element.");
         }
+        if(mDestroyed) {
+            throw new IllegalStateException("Object already destroyed.");
+        }
+        mDestroyed = true;
         mRS.nElementDestroy(mID);
-        mID = 0;
     }
 
 
@@ -206,7 +209,7 @@
                     if (en.mIsNormalized) {
                         norm = 1;
                     }
-                    rs.nElementAdd(en.mType.mID, en.mKind.mID, norm, en.mBits);
+                    rs.nElementAdd(en.mKind.mID, en.mType.mID, norm, en.mBits);
                 }
             }
             int id = rs.nElementCreate();
diff --git a/graphics/java/android/renderscript/Primitive.java b/graphics/java/android/renderscript/Primitive.java
new file mode 100644
index 0000000..7925cac
--- /dev/null
+++ b/graphics/java/android/renderscript/Primitive.java
@@ -0,0 +1,37 @@
+/*
+ * 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 android.renderscript;
+
+/**
+ * @hide
+ **/
+public enum Primitive {
+    POINT (0),
+    LINE (1),
+    LINE_STRIP (2),
+    TRIANGLE (3),
+    TRIANGLE_STRIP (4),
+    TRIANGLE_FAN (5);
+
+    int mID;
+    Primitive(int id) {
+        mID = id;
+    }
+}
+
+
+
diff --git a/graphics/java/android/renderscript/ProgramFragment.java b/graphics/java/android/renderscript/ProgramFragment.java
index c228cf2..09c4d9a 100644
--- a/graphics/java/android/renderscript/ProgramFragment.java
+++ b/graphics/java/android/renderscript/ProgramFragment.java
@@ -46,8 +46,11 @@
     }
 
     public void destroy() {
+        if(mDestroyed) {
+            throw new IllegalStateException("Object already destroyed.");
+        }
+        mDestroyed = true;
         mRS.nProgramFragmentStoreDestroy(mID);
-        mID = 0;
     }
 
     public void bindTexture(Allocation va, int slot)
diff --git a/graphics/java/android/renderscript/ProgramStore.java b/graphics/java/android/renderscript/ProgramStore.java
index 9039621..f8b59bd 100644
--- a/graphics/java/android/renderscript/ProgramStore.java
+++ b/graphics/java/android/renderscript/ProgramStore.java
@@ -81,8 +81,11 @@
     }
 
     public void destroy() {
+        if(mDestroyed) {
+            throw new IllegalStateException("Object already destroyed.");
+        }
+        mDestroyed = true;
         mRS.nProgramFragmentStoreDestroy(mID);
-        mID = 0;
     }
 
 
diff --git a/graphics/java/android/renderscript/ProgramVertex.java b/graphics/java/android/renderscript/ProgramVertex.java
index c4f7759..74c005f 100644
--- a/graphics/java/android/renderscript/ProgramVertex.java
+++ b/graphics/java/android/renderscript/ProgramVertex.java
@@ -34,8 +34,11 @@
     }
 
     public void destroy() {
+        if(mDestroyed) {
+            throw new IllegalStateException("Object already destroyed.");
+        }
+        mDestroyed = true;
         mRS.nProgramVertexDestroy(mID);
-        mID = 0;
     }
 
     public void bindAllocation(MatrixAllocation va) {
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 0fb450e..77486b1 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -68,6 +68,8 @@
     native void nContextBindProgramFragmentStore(int pfs);
     native void nContextBindProgramFragment(int pf);
     native void nContextBindProgramVertex(int pf);
+    native void nContextAddDefineI32(String name, int value);
+    native void nContextAddDefineF(String name, float value);
 
     native void nAssignName(int obj, byte[] name);
     native int  nFileOpen(byte[] name);
@@ -98,6 +100,8 @@
     native void nAllocationSubData1D(int id, int off, int count, float[] d);
     native void nAllocationSubData2D(int id, int xoff, int yoff, int w, int h, int[] d);
     native void nAllocationSubData2D(int id, int xoff, int yoff, int w, int h, float[] d);
+    native void nAllocationRead(int id, int[] d);
+    native void nAllocationRead(int id, float[] d);
 
     native void nTriangleMeshDestroy(int id);
     native void nTriangleMeshBegin(int vertex, int index);
@@ -139,6 +143,8 @@
     native void nScriptCSetRoot(boolean isRoot);
     native void nScriptCSetScript(byte[] script, int offset, int length);
     native int  nScriptCCreate();
+    native void nScriptCAddDefineI32(String name, int value);
+    native void nScriptCAddDefineF(String name, float value);
 
     native void nSamplerDestroy(int sampler);
     native void nSamplerBegin();
@@ -178,6 +184,15 @@
     native void nLightSetColor(int l, float r, float g, float b);
     native void nLightSetPosition(int l, float x, float y, float z);
 
+    native void nSimpleMeshDestroy(int id);
+    native int  nSimpleMeshCreate(int batchID, int idxID, int[] vtxID, int prim);
+    native void nSimpleMeshBindVertex(int id, int alloc, int slot);
+    native void nSimpleMeshBindIndex(int id, int alloc);
+
+    native void nAnimationDestroy(int id);
+    native void nAnimationBegin(int attribCount, int keyframeCount);
+    native void nAnimationAdd(float time, float[] attribs);
+    native int  nAnimationCreate();
 
     private int     mDev;
     private int     mContext;
@@ -188,7 +203,7 @@
     ///////////////////////////////////////////////////////////////////////////////////
     //
 
-    RenderScript(Surface sur) {
+    public RenderScript(Surface sur) {
         mSurface = sur;
         mDev = nDeviceCreate();
         mContext = nContextCreate(mDev, mSurface, 0);
diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java
index 9696cea..1c7b32b 100644
--- a/graphics/java/android/renderscript/Script.java
+++ b/graphics/java/android/renderscript/Script.java
@@ -28,8 +28,11 @@
     }
 
     public void destroy() {
+        if(mDestroyed) {
+            throw new IllegalStateException("Object already destroyed.");
+        }
+        mDestroyed = true;
         mRS.nScriptDestroy(mID);
-        mID = 0;
     }
 
     public void bindAllocation(Allocation va, int slot) {
diff --git a/graphics/java/android/renderscript/ScriptC.java b/graphics/java/android/renderscript/ScriptC.java
index 0592f5d..bb99e23 100644
--- a/graphics/java/android/renderscript/ScriptC.java
+++ b/graphics/java/android/renderscript/ScriptC.java
@@ -16,26 +16,32 @@
 
 package android.renderscript;
 
+import android.content.res.Resources;
+import android.util.Log;
+
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Map.Entry;
+import java.util.HashMap;
 
-import android.content.res.Resources;
-
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
 
 /**
  * @hide
  **/
 public class ScriptC extends Script {
+    private static final String TAG = "ScriptC";
+
     ScriptC(int id, RenderScript rs) {
         super(id, rs);
     }
 
-
-
-
     public static class Builder extends Script.Builder {
         byte[] mProgram;
         int mProgramLength;
+        HashMap<String,Integer> mIntDefines = new HashMap();
+        HashMap<String,Float> mFloatDefines = new HashMap();
 
         public Builder(RenderScript rs) {
             super(rs);
@@ -63,7 +69,7 @@
             }
         }
 
-        public void  setScript(InputStream is) throws IOException {
+        public void setScript(InputStream is) throws IOException {
             byte[] buf = new byte[1024];
             int currentPos = 0;
             while(true) {
@@ -88,19 +94,68 @@
             b.mRS.nScriptCBegin();
             b.transferCreate();
 
-            b.mRS.nScriptCSetScript(b.mProgram, 0, b.mProgramLength);
+            for (Entry<String,Integer> e: b.mIntDefines.entrySet()) {
+                b.mRS.nScriptCAddDefineI32(e.getKey(), e.getValue().intValue());
+            }
+            for (Entry<String,Float> e: b.mFloatDefines.entrySet()) {
+                b.mRS.nScriptCAddDefineF(e.getKey(), e.getValue().floatValue());
+            }
 
+            b.mRS.nScriptCSetScript(b.mProgram, 0, b.mProgramLength);
 
             int id = b.mRS.nScriptCCreate();
             ScriptC obj = new ScriptC(id, b.mRS);
             b.transferObject(obj);
+
             return obj;
         }
 
+        public void addDefine(String name, int value) {
+            mIntDefines.put(name, value);
+        }
+
+        public void addDefine(String name, float value) {
+            mFloatDefines.put(name, value);
+        }
+
+        /**
+         * Takes the all public static final fields for a class, and adds defines
+         * for them, using the name of the field as the name of the define.
+         */
+        public void addDefines(Class cl) {
+            addDefines(cl.getFields(), (Modifier.STATIC | Modifier.FINAL | Modifier.PUBLIC), null);
+        }
+
+        /**
+         * Takes the all public fields for an object, and adds defines
+         * for them, using the name of the field as the name of the define.
+         */
+        public void addDefines(Object o) {
+            addDefines(o.getClass().getFields(), Modifier.PUBLIC, o);
+        }
+
+        void addDefines(Field[] fields, int mask, Object o) {
+            for (Field f: fields) {
+                try {
+                    if ((f.getModifiers() & mask) == mask) {
+                        Class t = f.getType();
+                        if (t == int.class) {
+                            mIntDefines.put(f.getName(), f.getInt(o));
+                        }
+                        else if (t == float.class) {
+                            mFloatDefines.put(f.getName(), f.getFloat(o));
+                        }
+                    }
+                } catch (IllegalAccessException ex) {
+                    // TODO: Do we want this log?
+                    Log.d(TAG, "addDefines skipping field " + f.getName());
+                }
+            }
+        }
+
         public ScriptC create() {
             return internalCreate(this);
         }
     }
-
 }
 
diff --git a/graphics/java/android/renderscript/SimpleMesh.java b/graphics/java/android/renderscript/SimpleMesh.java
new file mode 100644
index 0000000..484849b
--- /dev/null
+++ b/graphics/java/android/renderscript/SimpleMesh.java
@@ -0,0 +1,179 @@
+/*
+ * 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 android.renderscript;
+
+import android.util.Config;
+import android.util.Log;
+
+/**
+ * @hide
+ *
+ **/
+public class SimpleMesh extends BaseObj {
+    Type[] mVertexTypes;
+    Type mIndexType;
+    //Type mBatcheType;
+    Primitive mPrimitive;
+
+    SimpleMesh(int id, RenderScript rs) {
+        super(rs);
+        mID = id;
+    }
+
+    public void destroy() {
+        if(mDestroyed) {
+            throw new IllegalStateException("Object already destroyed.");
+        }
+        mDestroyed = true;
+        mRS.nSimpleMeshDestroy(mID);
+    }
+
+    public void bindVertexAllocation(Allocation a, int slot) {
+        mRS.nSimpleMeshBindVertex(mID, a.mID, slot);
+    }
+
+    public void bindIndexAllocation(Allocation a) {
+        mRS.nSimpleMeshBindIndex(mID, a.mID);
+    }
+
+    public Allocation createVertexAllocation(int slot) {
+        return Allocation.createTyped(mRS, mVertexTypes[slot]);
+    }
+
+    public Allocation createIndexAllocation() {
+        return Allocation.createTyped(mRS, mIndexType);
+    }
+
+
+    public static class Builder {
+        RenderScript mRS;
+
+        class Entry {
+            Type t;
+            Element e;
+            int size;
+        }
+
+        int mVertexTypeCount;
+        Entry[] mVertexTypes;
+        Entry mIndexType;
+        //Entry mBatchType;
+        Primitive mPrimitive;
+
+
+        public Builder(RenderScript rs) {
+            mRS = rs;
+            mVertexTypeCount = 0;
+            mVertexTypes = new Entry[16];
+            mIndexType = new Entry();
+        }
+
+        public int addVertexType(Type t) throws IllegalStateException {
+            if(mVertexTypeCount >= mVertexTypes.length) {
+                throw new IllegalStateException("Max vertex types exceeded.");
+            }
+
+            int addedIndex = mVertexTypeCount;
+            mVertexTypes[mVertexTypeCount] = new Entry();
+            mVertexTypes[mVertexTypeCount].t = t;
+            mVertexTypeCount++;
+            return addedIndex;
+        }
+
+        public int addVertexType(Element e, int size) throws IllegalStateException {
+            if(mVertexTypeCount >= mVertexTypes.length) {
+                throw new IllegalStateException("Max vertex types exceeded.");
+            }
+
+            int addedIndex = mVertexTypeCount;
+            mVertexTypes[mVertexTypeCount] = new Entry();
+            mVertexTypes[mVertexTypeCount].e = e;
+            mVertexTypes[mVertexTypeCount].size = size;
+            mVertexTypeCount++;
+            return addedIndex;
+        }
+
+        public void setIndexType(Type t) {
+            mIndexType.t = t;
+            mIndexType.e = null;
+            mIndexType.size = 0;
+        }
+
+        public void setIndexType(Element e, int size) {
+            mIndexType.t = null;
+            mIndexType.e = e;
+            mIndexType.size = size;
+        }
+
+        public void setPrimitive(Primitive p) {
+            mPrimitive = p;
+        }
+
+
+        Type newType(Element e, int size) {
+            Type.Builder tb = new Type.Builder(mRS, e);
+            tb.add(Dimension.X, size);
+            return tb.create();
+        }
+
+        static synchronized SimpleMesh internalCreate(RenderScript rs, Builder b) {
+            Type[] toDestroy = new Type[18];
+            int toDestroyCount = 0;
+
+            int indexID = 0;
+            if(b.mIndexType.t != null) {
+                indexID = b.mIndexType.t.mID;
+            } else if(b.mIndexType.size != 0) {
+                b.mIndexType.t = b.newType(b.mIndexType.e, b.mIndexType.size);
+                indexID = b.mIndexType.t.mID;
+                toDestroy[toDestroyCount++] = b.mIndexType.t;
+            }
+
+            int[] IDs = new int[b.mVertexTypeCount];
+            for(int ct=0; ct < b.mVertexTypeCount; ct++) {
+                if(b.mVertexTypes[ct].t != null) {
+                    IDs[ct] = b.mVertexTypes[ct].t.mID;
+                } else {
+                    b.mVertexTypes[ct].t = b.newType(b.mVertexTypes[ct].e, b.mVertexTypes[ct].size);
+                    IDs[ct] = b.mVertexTypes[ct].t.mID;
+                    toDestroy[toDestroyCount++] = b.mVertexTypes[ct].t;
+                }
+            }
+
+            int id = rs.nSimpleMeshCreate(0, indexID, IDs, b.mPrimitive.mID);
+            for(int ct=0; ct < toDestroyCount; ct++) {
+                toDestroy[ct].destroy();
+            }
+
+            return new SimpleMesh(id, rs);
+        }
+
+        public SimpleMesh create() {
+            Log.e("rs", "SimpleMesh create");
+            SimpleMesh sm = internalCreate(mRS, this);
+            sm.mVertexTypes = new Type[mVertexTypeCount];
+            for(int ct=0; ct < mVertexTypeCount; ct++) {
+                sm.mVertexTypes[ct] = mVertexTypes[ct].t;
+            }
+            sm.mIndexType = mIndexType.t;
+            sm.mPrimitive = mPrimitive;
+            return sm;
+        }
+    }
+
+}
+
diff --git a/graphics/java/android/renderscript/Type.java b/graphics/java/android/renderscript/Type.java
index 4078c8a..a5fc603 100644
--- a/graphics/java/android/renderscript/Type.java
+++ b/graphics/java/android/renderscript/Type.java
@@ -16,31 +16,31 @@
 
 package android.renderscript;
 
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import android.content.res.Resources;
-import android.os.Bundle;
 import android.util.Config;
 import android.util.Log;
 
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 
 /**
  * @hide
  *
  **/
 public class Type extends BaseObj {
+    Dimension[] mDimensions;
+    int[] mValues;
+    Element mElement;
+
+
     Type(int id, RenderScript rs) {
         super(rs);
         mID = id;
     }
 
     public void destroy() {
+        if(mDestroyed) {
+            throw new IllegalStateException("Object already destroyed.");
+        }
+        mDestroyed = true;
         mRS.nTypeDestroy(mID);
-        mID = 0;
     }
 
     public static class Builder {
@@ -85,7 +85,15 @@
         }
 
         public Type create() {
-            return internalCreate(mRS, this);
+            Type t = internalCreate(mRS, this);
+            t.mElement = mElement;
+            t.mDimensions = new Dimension[mEntryCount];
+            t.mValues = new int[mEntryCount];
+            for(int ct=0; ct < mEntryCount; ct++) {
+                t.mDimensions[ct] = mEntries[ct].mDim;
+                t.mValues[ct] = mEntries[ct].mValue;
+            }
+            return t;
         }
     }
 
diff --git a/graphics/jni/Android.mk b/graphics/jni/Android.mk
index a19134d..a6abd8c 100644
--- a/graphics/jni/Android.mk
+++ b/graphics/jni/Android.mk
@@ -1,4 +1,3 @@
-ifeq ($(BUILD_RENDERSCRIPT),true)
 
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
@@ -33,7 +32,7 @@
 LOCAL_MODULE:= librs_jni
 LOCAL_ADDITIONAL_DEPENDENCIES += $(rs_generated_source)
 LOCAL_MODULE_TAGS := optional
+LOCAL_REQUIRED_MODULES := libRS
 
 include $(BUILD_SHARED_LIBRARY)
 
-endif
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index e2a8a27..285fdc0 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -389,6 +389,27 @@
     _env->ReleaseFloatArrayElements(data, ptr, JNI_ABORT);
 }
 
+static void
+nAllocationRead_i(JNIEnv *_env, jobject _this, jint alloc, jintArray data)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    jint len = _env->GetArrayLength(data);
+    LOG_API("nAllocationRead_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
+    jint *ptr = _env->GetIntArrayElements(data, NULL);
+    rsAllocationData((RsAllocation)alloc, ptr);
+    _env->ReleaseIntArrayElements(data, ptr, JNI_COMMIT);
+}
+
+static void
+nAllocationRead_f(JNIEnv *_env, jobject _this, jint alloc, jfloatArray data)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    jint len = _env->GetArrayLength(data);
+    LOG_API("nAllocationRead_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
+    jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
+    rsAllocationData((RsAllocation)alloc, ptr);
+    _env->ReleaseFloatArrayElements(data, ptr, JNI_COMMIT);
+}
 
 
 // -----------------------------------
@@ -765,6 +786,26 @@
     return (jint)rsScriptCCreate();
 }
 
+static void
+nScriptCAddDefineI32(JNIEnv *_env, jobject _this, jstring name, jint value)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    const char* n = _env->GetStringUTFChars(name, NULL);
+    LOG_API("nScriptCAddDefineI32, con(%p) name(%s) value(%d)", con, n, value);
+    rsScriptCSetDefineI32(n, value);
+    _env->ReleaseStringUTFChars(name, n);
+}
+
+static void
+nScriptCAddDefineF(JNIEnv *_env, jobject _this, jstring name, jfloat value)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    const char* n = _env->GetStringUTFChars(name, NULL);
+    LOG_API("nScriptCAddDefineF, con(%p) name(%s) value(%f)", con, n, value);
+    rsScriptCSetDefineF(n, value);
+    _env->ReleaseStringUTFChars(name, n);
+}
+
 // ---------------------------------------------------------------------------
 
 static void
@@ -985,6 +1026,27 @@
     rsContextBindProgramVertex((RsProgramVertex)pf);
 }
 
+static void
+nContextAddDefineI32(JNIEnv *_env, jobject _this, jstring name, jint value)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    const char* n = _env->GetStringUTFChars(name, NULL);
+    LOG_API("nScriptCAddDefineI32, con(%p) name(%s) value(%d)", con, n, value);
+    rsContextSetDefineI32(n, value);
+    _env->ReleaseStringUTFChars(name, n);
+}
+
+static void
+nContextAddDefineF(JNIEnv *_env, jobject _this, jstring name, jfloat value)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    const char* n = _env->GetStringUTFChars(name, NULL);
+    LOG_API("nScriptCAddDefineF, con(%p) name(%s) value(%f)", con, n, value);
+    rsContextSetDefineF(n, value);
+    _env->ReleaseStringUTFChars(name, n);
+}
+
+
 // ---------------------------------------------------------------------------
 
 static void
@@ -1079,6 +1141,45 @@
 
 // ---------------------------------------------------------------------------
 
+static void
+nSimpleMeshDestroy(JNIEnv *_env, jobject _this, jint s)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nSimpleMeshDestroy, con(%p), SimpleMesh(%p)", con, (RsSimpleMesh)s);
+    rsSimpleMeshDestroy((RsSimpleMesh)s);
+}
+
+static jint
+nSimpleMeshCreate(JNIEnv *_env, jobject _this, jint batchID, jint indexID, jintArray vtxIDs, jint primID)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    jint len = _env->GetArrayLength(vtxIDs);
+    LOG_API("nSimpleMeshCreate, con(%p), batchID(%i), indexID(%i), vtxIDs.len(%i), primID(%i)",
+            con, batchID, indexID, len, primID);
+    jint *ptr = _env->GetIntArrayElements(vtxIDs, NULL);
+    int id = (int)rsSimpleMeshCreate((void *)batchID, (void *)indexID, (void **)ptr, len, primID);
+    _env->ReleaseIntArrayElements(vtxIDs, ptr, 0/*JNI_ABORT*/);
+    return id;
+}
+
+static void
+nSimpleMeshBindVertex(JNIEnv *_env, jobject _this, jint s, jint alloc, jint slot)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nSimpleMeshBindVertex, con(%p), SimpleMesh(%p), Alloc(%p), slot(%i)", con, (RsSimpleMesh)s, (RsAllocation)alloc, slot);
+    rsSimpleMeshBindVertex((RsSimpleMesh)s, (RsAllocation)alloc, slot);
+}
+
+static void
+nSimpleMeshBindIndex(JNIEnv *_env, jobject _this, jint s, jint alloc)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nSimpleMeshBindIndex, con(%p), SimpleMesh(%p), Alloc(%p)", con, (RsSimpleMesh)s, (RsAllocation)alloc);
+    rsSimpleMeshBindIndex((RsSimpleMesh)s, (RsAllocation)alloc);
+}
+
+// ---------------------------------------------------------------------------
+
 
 static const char *classPathName = "android/renderscript/RenderScript";
 
@@ -1117,6 +1218,8 @@
 {"nAllocationSubData1D",           "(III[F)V",                             (void*)nAllocationSubData1D_f },
 {"nAllocationSubData2D",           "(IIIII[I)V",                           (void*)nAllocationSubData2D_i },
 {"nAllocationSubData2D",           "(IIIII[F)V",                           (void*)nAllocationSubData2D_f },
+{"nAllocationRead",                "(I[I)V",                               (void*)nAllocationRead_i },
+{"nAllocationRead",                "(I[F)V",                               (void*)nAllocationRead_f },
 
 {"nTriangleMeshDestroy",           "(I)V",                                 (void*)nTriangleMeshDestroy },
 {"nTriangleMeshBegin",             "(II)V",                                (void*)nTriangleMeshBegin },
@@ -1158,6 +1261,8 @@
 {"nScriptCSetRoot",                "(Z)V",                                 (void*)nScriptCSetRoot },
 {"nScriptCSetScript",              "([BII)V",                              (void*)nScriptCSetScript },
 {"nScriptCCreate",                 "()I",                                  (void*)nScriptCCreate },
+{"nScriptCAddDefineI32",           "(Ljava/lang/String;I)V",               (void*)nScriptCAddDefineI32 },
+{"nScriptCAddDefineF",             "(Ljava/lang/String;F)V",               (void*)nScriptCAddDefineF },
 
 {"nProgramFragmentStoreBegin",     "(II)V",                                (void*)nProgramFragmentStoreBegin },
 {"nProgramFragmentStoreDepthFunc", "(I)V",                                 (void*)nProgramFragmentStoreDepthFunc },
@@ -1202,6 +1307,11 @@
 {"nSamplerSet",                    "(II)V",                                (void*)nSamplerSet },
 {"nSamplerCreate",                 "()I",                                  (void*)nSamplerCreate },
 
+{"nSimpleMeshDestroy",             "(I)V",                                 (void*)nSimpleMeshDestroy },
+{"nSimpleMeshCreate",              "(II[II)I",                             (void*)nSimpleMeshCreate },
+{"nSimpleMeshBindVertex",          "(III)V",                               (void*)nSimpleMeshBindVertex },
+{"nSimpleMeshBindIndex",           "(II)V",                                (void*)nSimpleMeshBindIndex },
+
 };
 
 static int registerFuncs(JNIEnv *_env)
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 0010d84..7e5ff61 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -25,14 +25,13 @@
 #include <OMX_Core.h>
 #include <OMX_Video.h>
 
-#define IOMX_USES_SOCKETS       0
-
 namespace android {
 
 class IMemory;
 class IOMXObserver;
 class IOMXRenderer;
 class ISurface;
+class Surface;
 
 class IOMX : public IInterface {
 public:
@@ -41,12 +40,6 @@
     typedef void *buffer_id;
     typedef void *node_id;
 
-#if IOMX_USES_SOCKETS
-    // If successful, returns a socket descriptor used for further
-    // communication. Caller assumes ownership of "*sd".
-    virtual status_t connect(int *sd) = 0;
-#endif
-
     virtual status_t list_nodes(List<String8> *list) = 0;
 
     virtual status_t allocate_node(const char *name, node_id *node) = 0;
@@ -78,7 +71,6 @@
     virtual status_t free_buffer(
             node_id node, OMX_U32 port_index, buffer_id buffer) = 0;
 
-#if !IOMX_USES_SOCKETS
     virtual status_t observe_node(
             node_id node, const sp<IOMXObserver> &observer) = 0;
 
@@ -89,7 +81,6 @@
             buffer_id buffer,
             OMX_U32 range_offset, OMX_U32 range_length,
             OMX_U32 flags, OMX_TICKS timestamp) = 0;
-#endif
 
     virtual sp<IOMXRenderer> createRenderer(
             const sp<ISurface> &surface,
@@ -97,6 +88,16 @@
             OMX_COLOR_FORMATTYPE colorFormat,
             size_t encodedWidth, size_t encodedHeight,
             size_t displayWidth, size_t displayHeight) = 0;
+
+    // Note: This method is _not_ virtual, it exists as a wrapper around
+    // the virtual "createRenderer" method above facilitating extraction
+    // of the ISurface from a regular Surface.
+    sp<IOMXRenderer> createRenderer(
+            const sp<Surface> &surface,
+            const char *componentName,
+            OMX_COLOR_FORMATTYPE colorFormat,
+            size_t encodedWidth, size_t encodedHeight,
+            size_t displayWidth, size_t displayHeight);
 };
 
 struct omx_message {
@@ -105,14 +106,6 @@
         EMPTY_BUFFER_DONE,
         FILL_BUFFER_DONE,
 
-#if IOMX_USES_SOCKETS
-        EMPTY_BUFFER,
-        FILL_BUFFER,
-        SEND_COMMAND,
-        DISCONNECT,
-        DISCONNECTED,
-#endif
-
         // reserved for OMXDecoder use.
         START,
         INITIAL_FILL_BUFFER,
diff --git a/include/media/stagefright/OMXClient.h b/include/media/stagefright/OMXClient.h
index 454c38b..7027e1b 100644
--- a/include/media/stagefright/OMXClient.h
+++ b/include/media/stagefright/OMXClient.h
@@ -87,32 +87,14 @@
     status_t registerObserver(IOMX::node_id node, OMXObserver *observer);
     void unregisterObserver(IOMX::node_id node);
 
-    status_t fillBuffer(IOMX::node_id node, IOMX::buffer_id buffer);
-
-    status_t emptyBuffer(
-            IOMX::node_id node, IOMX::buffer_id buffer,
-            OMX_U32 range_offset, OMX_U32 range_length,
-            OMX_U32 flags, OMX_TICKS timestamp);
-
-    status_t send_command(
-            IOMX::node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param);
-
 private:
     sp<IOMX> mOMX;
-
-    int mSock;
     Mutex mLock;
-    pthread_t mThread;
 
     KeyedVector<IOMX::node_id, OMXObserver *> mObservers;
 
     sp<OMXClientReflector> mReflector;
 
-#if IOMX_USES_SOCKETS
-    static void *ThreadWrapper(void *me);
-    void threadEntry();
-#endif
-
     bool onOMXMessage(const omx_message &msg);
 
     OMXClient(const OMXClient &);
diff --git a/include/ui/EGLUtils.h b/include/ui/EGLUtils.h
index 48777b6..a5bff81 100644
--- a/include/ui/EGLUtils.h
+++ b/include/ui/EGLUtils.h
@@ -31,6 +31,8 @@
 {
 public:
 
+    static const char *strerror(EGLint err);
+
     static status_t selectConfigForPixelFormat(
             EGLDisplay dpy,
             EGLint const* attrs,
diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h
index cb9bf94..68144b5 100644
--- a/include/ui/FramebufferNativeWindow.h
+++ b/include/ui/FramebufferNativeWindow.h
@@ -63,6 +63,7 @@
     static int lockBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
     static int queueBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
     static int query(android_native_window_t* window, int what, int* value);
+    static int perform(android_native_window_t* window, int operation, ...);
     
     framebuffer_device_t* fbDev;
     alloc_device_t* grDev;
diff --git a/include/ui/ISurface.h b/include/ui/ISurface.h
index adba45a..7909c2f 100644
--- a/include/ui/ISurface.h
+++ b/include/ui/ISurface.h
@@ -50,7 +50,7 @@
 public: 
     DECLARE_META_INTERFACE(Surface);
 
-    virtual sp<SurfaceBuffer> getBuffer() = 0; 
+    virtual sp<SurfaceBuffer> getBuffer(int usage) = 0; 
     
     class BufferHeap {
     public:
diff --git a/include/ui/Surface.h b/include/ui/Surface.h
index 5665c1f..4ff0e4a 100644
--- a/include/ui/Surface.h
+++ b/include/ui/Surface.h
@@ -35,8 +35,8 @@
 // ---------------------------------------------------------------------------
 
 class BufferMapper;
+class IOMX;
 class Rect;
-class MediaPlayerImpl;
 class Surface;
 class SurfaceComposerClient;
 struct per_client_cblk_t;
@@ -181,10 +181,10 @@
     // mediaplayer needs access to ISurface for display
     friend class MediaPlayer;
     friend class Test;
-    friend class MediaPlayerImpl;
+    friend class IOMX;
     const sp<ISurface>& getISurface() const { return mSurface; }
 
-    status_t getBufferLocked(int index);
+    status_t getBufferLocked(int index, int usage);
    
            status_t validate(per_client_cblk_t const* cblk) const;
     static void _send_dirty_region(layer_cblk_t* lcblk, const Region& dirty);
@@ -197,11 +197,13 @@
     static int lockBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
     static int queueBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
     static int query(android_native_window_t* window, int what, int* value);
+    static int perform(android_native_window_t* window, int operation, ...);
 
     int dequeueBuffer(android_native_buffer_t** buffer);
     int lockBuffer(android_native_buffer_t* buffer);
     int queueBuffer(android_native_buffer_t* buffer);
     int query(int what, int* value);
+    int perform(int operation, va_list args);
 
     status_t dequeueBuffer(sp<SurfaceBuffer>* buffer);
     status_t lockBuffer(const sp<SurfaceBuffer>& buffer);
@@ -217,6 +219,7 @@
     uint32_t                    mIdentity;
     uint32_t                    mWidth;
     uint32_t                    mHeight;
+    uint32_t                    mUsage;
     PixelFormat                 mFormat;
     uint32_t                    mFlags;
     mutable Region              mDirtyRegion;
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index 7da69b1..4c58e47 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -67,6 +67,11 @@
     NATIVE_WINDOW_FORMAT    = 2,
 };
 
+/* valid operations for the (*perform)() hook */
+enum {
+    NATIVE_WINDOW_SET_USAGE = 0
+};
+
 struct android_native_window_t 
 {
 #ifdef __cplusplus
@@ -142,11 +147,45 @@
      * Returns 0 on success or -errno on error.
      */
     int     (*query)(struct android_native_window_t* window,
-            int what, int* value);
+                int what, int* value);
     
-    void* reserved_proc[4];
+    /*
+     * hook used to perform various operations on the surface.
+     * (*perform)() is a generic mechanism to add functionality to
+     * android_native_window_t while keeping backward binary compatibility.
+     * 
+     * This hook should not be called directly, instead use the helper functions
+     * defined below.
+     * 
+     * The valid operations are:
+     *     NATIVE_WINDOW_SET_USAGE
+     *  
+     */
+    
+    int     (*perform)(struct android_native_window_t* window,
+                int operation, ... );
+    
+    void* reserved_proc[3];
 };
 
+
+/*
+ *  native_window_set_usage() sets the intended usage flags for the next
+ *  buffers acquired with (*lockBuffer)() and on.
+ *  By default (if this function is never called), a usage of
+ *      GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE
+ *  is assumed.
+ *  Calling this function will usually cause following buffers to be
+ *  reallocated.
+ */
+
+inline int native_window_set_usage(
+        struct android_native_window_t* window, int usage)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_USAGE, usage);
+}
+
+
 // ---------------------------------------------------------------------------
 
 /* FIXME: this is legacy for pixmaps */
diff --git a/keystore/java/android/security/ServiceCommand.java b/keystore/java/android/security/ServiceCommand.java
index dddf654..cefae40 100644
--- a/keystore/java/android/security/ServiceCommand.java
+++ b/keystore/java/android/security/ServiceCommand.java
@@ -121,15 +121,16 @@
         Reply reply = new Reply();
 
         if (!readBytes(buf, 4)) return null;
-        reply.len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8) |
-                ((((int) buf[2]) & 0xff) << 16) |
-                ((((int) buf[3]) & 0xff) << 24);
+        reply.len = ((((int) buf[0]) & 0xff) << 24) |
+                ((((int) buf[1]) & 0xff) << 16) |
+                ((((int) buf[2]) & 0xff) << 8) |
+                (((int) buf[3]) & 0xff);
 
         if (!readBytes(buf, 4)) return null;
-        reply.returnCode = (((int) buf[0]) & 0xff) |
-                ((((int) buf[1]) & 0xff) << 8) |
-                ((((int) buf[2]) & 0xff) << 16) |
-                ((((int) buf[3]) & 0xff) << 24);
+        reply.returnCode = ((((int) buf[0]) & 0xff) << 24) |
+                ((((int) buf[1]) & 0xff) << 16) |
+                ((((int) buf[2]) & 0xff) << 8) |
+                (((int) buf[3]) & 0xff);
 
         if (reply.len > BUFFER_LENGTH) {
             Log.e(mTag,"invalid reply length (" + reply.len + ")");
@@ -145,15 +146,15 @@
         byte[] data = (_data == null) ? new byte[0] : _data.getBytes();
         int len = data.length;
         // the length of data
-        buf[0] = (byte) (len & 0xff);
-        buf[1] = (byte) ((len >> 8) & 0xff);
-        buf[2] = (byte) ((len >> 16) & 0xff);
-        buf[3] = (byte) ((len >> 24) & 0xff);
+        buf[0] = (byte) ((len >> 24) & 0xff);
+        buf[1] = (byte) ((len >> 16) & 0xff);
+        buf[2] = (byte) ((len >> 8) & 0xff);
+        buf[3] = (byte) (len & 0xff);
         // the opcode of the command
-        buf[4] = (byte) (cmd & 0xff);
-        buf[5] = (byte) ((cmd >> 8) & 0xff);
-        buf[6] = (byte) ((cmd >> 16) & 0xff);
-        buf[7] = (byte) ((cmd >> 24) & 0xff);
+        buf[4] = (byte) ((cmd >> 24) & 0xff);
+        buf[5] = (byte) ((cmd >> 16) & 0xff);
+        buf[6] = (byte) ((cmd >> 8) & 0xff);
+        buf[7] = (byte) (cmd & 0xff);
         try {
             mOut.write(buf, 0, 8);
             mOut.write(data, 0, len);
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp
index 20db8a5..57a29f2 100644
--- a/libs/audioflinger/A2dpAudioInterface.cpp
+++ b/libs/audioflinger/A2dpAudioInterface.cpp
@@ -204,7 +204,7 @@
     mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL),
     // assume BT enabled to start, this is safe because its only the
     // enabled->disabled transition we are worried about
-    mBluetoothEnabled(true), mDevice(0)
+    mBluetoothEnabled(true), mDevice(0), mClosing(false)
 {
     // use any address by default
     strcpy(mA2dpAddress, "00:00:00:00:00:00");
@@ -258,7 +258,7 @@
     size_t remaining = bytes;
     status_t status = -1;
 
-    if (!mBluetoothEnabled) {
+    if (!mBluetoothEnabled || mClosing) {
         LOGW("A2dpAudioStreamOut::write(), but bluetooth disabled");
         goto Error;
     }
@@ -307,6 +307,11 @@
 {
     int result = 0;
 
+    if (mClosing) {
+        LOGV("Ignore standby, closing");
+        return result;
+    }
+
     Mutex::Autolock lock(mLock);
 
     if (!mStandby) {
@@ -335,6 +340,11 @@
         }
         param.remove(key);
     }
+    key = String8("closing");
+    if (param.get(key, value) == NO_ERROR) {
+        mClosing = (value == "true");
+        param.remove(key);
+    }
     key = AudioParameter::keyRouting;
     if (param.getInt(key, device) == NO_ERROR) {
         if (AudioSystem::isA2dpDevice((AudioSystem::audio_devices)device)) {
diff --git a/libs/audioflinger/A2dpAudioInterface.h b/libs/audioflinger/A2dpAudioInterface.h
index d6709e2..35a6e11 100644
--- a/libs/audioflinger/A2dpAudioInterface.h
+++ b/libs/audioflinger/A2dpAudioInterface.h
@@ -112,6 +112,7 @@
                 Mutex       mLock;
                 bool        mBluetoothEnabled;
                 uint32_t    mDevice;
+                bool        mClosing;
     };
 
     friend class A2dpAudioStreamOut;
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index d019097..77a126c 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -1512,6 +1512,10 @@
                     int name = getTrackName_l();
                     if (name < 0) break;
                     mTracks[i]->mName = name;
+                    // limit track sample rate to 2 x new output sample rate
+                    if (mTracks[i]->mCblk->sampleRate > 2 * sampleRate()) {
+                        mTracks[i]->mCblk->sampleRate = 2 * sampleRate();
+                    }
                 }
                 sendConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
             }
@@ -1856,9 +1860,7 @@
                          mSuspended) {
                 if (!mStandby) {
                     for (size_t i = 0; i < outputTracks.size(); i++) {
-                        mLock.unlock();
                         outputTracks[i]->stop();
-                        mLock.lock();
                     }
                     mStandby = true;
                     mBytesWritten = 0;
@@ -1899,9 +1901,9 @@
             if (!mSuspended) {
                 for (size_t i = 0; i < outputTracks.size(); i++) {
                     outputTracks[i]->write(curBuf, mFrameCount);
+                    mustSleep = false;
                 }
                 mStandby = false;
-                mustSleep = false;
                 mBytesWritten += mixBufferSize;
             }
         } else {
@@ -1931,11 +1933,14 @@
         outputTracks.clear();
     }
 
-    if (!mStandby) {
-        for (size_t i = 0; i < outputTracks.size(); i++) {
-            mLock.unlock();
-            outputTracks[i]->stop();
-            mLock.lock();
+    { // scope for the mLock
+
+        Mutex::Autolock _l(mLock);
+        if (!mStandby) {
+            LOGV("DuplicatingThread() exiting out of standby");
+            for (size_t i = 0; i < mOutputTracks.size(); i++) {
+                mOutputTracks[i]->destroy();
+            }
         }
     }
 
@@ -1953,9 +1958,11 @@
                                             mFormat,
                                             mChannelCount,
                                             frameCount);
-    thread->setStreamVolume(AudioSystem::NUM_STREAM_TYPES, 1.0f);
-    mOutputTracks.add(outputTrack);
-    LOGV("addOutputTrack() track %p, on thread %p", outputTrack, thread);
+    if (outputTrack->cblk() != NULL) {
+        thread->setStreamVolume(AudioSystem::NUM_STREAM_TYPES, 1.0f);
+        mOutputTracks.add(outputTrack);
+        LOGV("addOutputTrack() track %p, on thread %p", outputTrack, thread);
+    }
 }
 
 void AudioFlinger::DuplicatingThread::removeOutputTrack(MixerThread *thread)
@@ -1963,6 +1970,7 @@
     Mutex::Autolock _l(mLock);
     for (size_t i = 0; i < mOutputTracks.size(); i++) {
         if (mOutputTracks[i]->thread() == (ThreadBase *)thread) {
+            mOutputTracks[i]->destroy();
             mOutputTracks.removeAt(i);
             return;
         }
@@ -2452,20 +2460,23 @@
 {
 
     PlaybackThread *playbackThread = (PlaybackThread *)thread.unsafe_get();
-    mCblk->out = 1;
-    mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
-    mCblk->volume[0] = mCblk->volume[1] = 0x1000;
-    mOutBuffer.frameCount = 0;
-    mWaitTimeMs = (playbackThread->frameCount() * 2 * 1000) / playbackThread->sampleRate();
-
-    LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p mWaitTimeMs %d",
-            mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd, mWaitTimeMs);
-
+    if (mCblk != NULL) {
+        mCblk->out = 1;
+        mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+        mCblk->volume[0] = mCblk->volume[1] = 0x1000;
+        mOutBuffer.frameCount = 0;
+        mWaitTimeMs = (playbackThread->frameCount() * 2 * 1000) / playbackThread->sampleRate();
+        playbackThread->mTracks.add(this);
+        LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p mWaitTimeMs %d",
+                mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd, mWaitTimeMs);
+    } else {
+        LOGW("Error creating output track on thread %p", playbackThread);
+    }
 }
 
 AudioFlinger::PlaybackThread::OutputTrack::~OutputTrack()
 {
-    stop();
+    clearBufferQueue();
 }
 
 status_t AudioFlinger::PlaybackThread::OutputTrack::start()
@@ -2904,7 +2915,7 @@
                     if (mReqChannelCount != mActiveTrack->channelCount()) {
                         mActiveTrack.clear();
                     } else {
-                        mActiveTrack->mState == TrackBase::ACTIVE;
+                        mActiveTrack->mState = TrackBase::ACTIVE;
                     }
                     mStartStopCond.broadcast();
                 }
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 4ba5977..65c148e 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -245,6 +245,7 @@
             virtual status_t    start() = 0;
             virtual void        stop() = 0;
                     sp<IMemory> getCblk() const;
+                    audio_track_cblk_t* cblk() const { return mCblk; }
 
         protected:
             friend class ThreadBase;
@@ -260,10 +261,6 @@
             virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
             virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
 
-            audio_track_cblk_t* cblk() const {
-                return mCblk;
-            }
-
             int format() const {
                 return mFormat;
             }
@@ -528,6 +525,7 @@
     private:
 
         friend class AudioFlinger;
+        friend class OutputTrack;
         friend class Track;
         friend class TrackBase;
         friend class MixerThread;
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
index 375cf6c..7075842 100644
--- a/libs/rs/Android.mk
+++ b/libs/rs/Android.mk
@@ -1,4 +1,3 @@
-ifeq ($(BUILD_RENDERSCRIPT),true)
 
 LOCAL_PATH:=$(call my-dir)
 
@@ -15,17 +14,8 @@
 LOCAL_MODULE_CLASS := EXECUTABLES
 intermediates := $(local-intermediates-dir)
 
-GEN := $(addprefix $(intermediates)/, \
-            lex.yy.c \
-        )
-$(GEN):	PRIVATE_CUSTOM_TOOL = flex -o $@ $<
-
-$(intermediates)/lex.yy.c : $(LOCAL_PATH)/spec.lex
-	$(transform-generated-source)
-
-$(LOCAL_PATH)/rsg_generator.c : $(intermediates)/lex.yy.c
-
 LOCAL_SRC_FILES:= \
+    spec.l \
     rsg_generator.c
 
 include $(BUILD_HOST_EXECUTABLE)
@@ -99,6 +89,7 @@
 	rsScript.cpp \
 	rsScriptC.cpp \
 	rsScriptC_Lib.cpp \
+	rsSimpleMesh.cpp \
 	rsThreadIO.cpp \
 	rsType.cpp \
 	rsTriangleMesh.cpp
@@ -115,4 +106,3 @@
             java \
     	))
 
-endif
\ No newline at end of file
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index 1d14f70..d7d572e 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -25,7 +25,7 @@
 #endif
 
 //////////////////////////////////////////////////////
-// 
+//
 
 typedef void * RsAdapter1D;
 typedef void * RsAdapter2D;
@@ -38,6 +38,7 @@
 typedef void * RsScript;
 typedef void * RsScriptBasicTemp;
 typedef void * RsTriangleMesh;
+typedef void * RsSimpleMesh;
 typedef void * RsType;
 typedef void * RsLight;
 
@@ -51,6 +52,8 @@
 RsContext rsContextCreate(RsDevice, void *, uint32_t version);
 void rsContextDestroy(RsContext);
 
+#define RS_MAX_TEXTURE 2
+
 enum RsDataType {
     RS_TYPE_FLOAT,
     RS_TYPE_UNSIGNED,
@@ -59,22 +62,22 @@
 
 enum RsDataKind {
     RS_KIND_USER,
-    RS_KIND_RED, 
-    RS_KIND_GREEN, 
-    RS_KIND_BLUE, 
-    RS_KIND_ALPHA, 
-    RS_KIND_LUMINANCE, 
+    RS_KIND_RED,
+    RS_KIND_GREEN,
+    RS_KIND_BLUE,
+    RS_KIND_ALPHA,
+    RS_KIND_LUMINANCE,
     RS_KIND_INTENSITY,
-    RS_KIND_X, 
-    RS_KIND_Y, 
-    RS_KIND_Z, 
+    RS_KIND_X,
+    RS_KIND_Y,
+    RS_KIND_Z,
     RS_KIND_W,
-    RS_KIND_S, 
-    RS_KIND_T, 
-    RS_KIND_Q, 
+    RS_KIND_S,
+    RS_KIND_T,
+    RS_KIND_Q,
     RS_KIND_R,
-    RS_KIND_NX, 
-    RS_KIND_NY, 
+    RS_KIND_NX,
+    RS_KIND_NY,
     RS_KIND_NZ,
     RS_KIND_INDEX
 };
@@ -86,7 +89,7 @@
     RS_ELEMENT_USER_I16,
     RS_ELEMENT_USER_U32,
     RS_ELEMENT_USER_I32,
-    RS_ELEMENT_USER_FLOAT, 
+    RS_ELEMENT_USER_FLOAT,
 
     RS_ELEMENT_A_8,          // 7
     RS_ELEMENT_RGB_565,      // 8
@@ -96,14 +99,14 @@
     RS_ELEMENT_RGBA_8888,    // 12
 
     RS_ELEMENT_INDEX_16, //13
-    RS_ELEMENT_INDEX_32, 
-    RS_ELEMENT_XY_F32, 
-    RS_ELEMENT_XYZ_F32, 
-    RS_ELEMENT_ST_XY_F32, 
-    RS_ELEMENT_ST_XYZ_F32, 
+    RS_ELEMENT_INDEX_32,
+    RS_ELEMENT_XY_F32,
+    RS_ELEMENT_XYZ_F32,
+    RS_ELEMENT_ST_XY_F32,
+    RS_ELEMENT_ST_XYZ_F32,
     RS_ELEMENT_NORM_XYZ_F32,
     RS_ELEMENT_NORM_ST_XYZ_F32,
-};  
+};
 
 enum RsSamplerParam {
     RS_SAMPLER_MIN_FILTER,
@@ -111,7 +114,7 @@
     RS_SAMPLER_WRAP_S,
     RS_SAMPLER_WRAP_T,
     RS_SAMPLER_WRAP_R
-};  
+};
 
 enum RsSamplerValue {
     RS_SAMPLER_NEAREST,
@@ -119,7 +122,7 @@
     RS_SAMPLER_LINEAR_MIP_LINEAR,
     RS_SAMPLER_WRAP,
     RS_SAMPLER_CLAMP
-};  
+};
 
 enum RsDimension {
     RS_DIMENSION_X,
@@ -128,9 +131,9 @@
     RS_DIMENSION_LOD,
     RS_DIMENSION_FACE,
 
-    RS_DIMENSION_ARRAY_0 = 100, 
-    RS_DIMENSION_ARRAY_1, 
-    RS_DIMENSION_ARRAY_2, 
+    RS_DIMENSION_ARRAY_0 = 100,
+    RS_DIMENSION_ARRAY_1,
+    RS_DIMENSION_ARRAY_2,
     RS_DIMENSION_ARRAY_3,
     RS_DIMENSION_MAX = RS_DIMENSION_ARRAY_3
 };
diff --git a/libs/rs/RenderScriptEnv.h b/libs/rs/RenderScriptEnv.h
index 7a5556e..5eb8912 100644
--- a/libs/rs/RenderScriptEnv.h
+++ b/libs/rs/RenderScriptEnv.h
@@ -11,6 +11,7 @@
 typedef void * RsScript;
 typedef void * RsScriptBasicTemp;
 typedef void * RsTriangleMesh;
+typedef void * RsSimpleMesh;
 typedef void * RsType;
 typedef void * RsProgramFragment;
 typedef void * RsProgramFragmentStore;
diff --git a/libs/rs/java/Fall/AndroidManifest.xml b/libs/rs/java/Fall/AndroidManifest.xml
index f4f96a1..f646d0d 100644
--- a/libs/rs/java/Fall/AndroidManifest.xml
+++ b/libs/rs/java/Fall/AndroidManifest.xml
@@ -5,6 +5,7 @@
     <application android:label="FallRS">
 
         <activity
+            android:screenOrientation="portrait"
             android:name="Fall"
             android:theme="@android:style/Theme.NoTitleBar">
 
diff --git a/libs/rs/java/Fall/res/drawable-hdpi/leaves.png b/libs/rs/java/Fall/res/drawable-hdpi/leaves.png
new file mode 100644
index 0000000..9eddd66
--- /dev/null
+++ b/libs/rs/java/Fall/res/drawable-hdpi/leaves.png
Binary files differ
diff --git a/libs/rs/java/Fall/res/drawable-hdpi/riverbed.jpg b/libs/rs/java/Fall/res/drawable-hdpi/riverbed.jpg
new file mode 100644
index 0000000..1698f28
--- /dev/null
+++ b/libs/rs/java/Fall/res/drawable-hdpi/riverbed.jpg
Binary files differ
diff --git a/libs/rs/java/Fall/res/raw/fall.c b/libs/rs/java/Fall/res/raw/fall.c
index 267b3ea..b18c124 100644
--- a/libs/rs/java/Fall/res/raw/fall.c
+++ b/libs/rs/java/Fall/res/raw/fall.c
@@ -27,15 +27,36 @@
 #define RSID_RIPPLE_INDEX 6
 #define RSID_DROP_X 7
 #define RSID_DROP_Y 8
+#define RSID_RUNNING 9
+#define RSID_LEAVES_COUNT 10
     
-#define RSID_TEXTURES 1
+#define RSID_RIPPLE_MAP 1
+#define RSID_REFRACTION_MAP 2
+#define RSID_LEAVES 3
 
-#define RSID_RIPPLE_MAP 2
+#define RSID_GL_STATE 4
+#define RSID_GL_WIDTH 0
+#define RSID_GL_HEIGHT 1
 
-#define RSID_REFRACTION_MAP 3
+#define LEAF_STRUCT_FIELDS_COUNT 11
+#define LEAF_STRUCT_X 0
+#define LEAF_STRUCT_Y 1
+#define LEAF_STRUCT_SCALE 2
+#define LEAF_STRUCT_ANGLE 3
+#define LEAF_STRUCT_SPIN 4
+#define LEAF_STRUCT_U1 5
+#define LEAF_STRUCT_U2 6
+#define LEAF_STRUCT_ALTITUDE 7
+#define LEAF_STRUCT_RIPPLED 8
+#define LEAF_STRUCT_DELTAX 9
+#define LEAF_STRUCT_DELTAY 10
+
+#define LEAVES_TEXTURES_COUNT 4
+
+#define LEAF_SIZE 0.55f
 
 #define REFRACTION 1.333f
-#define DAMP 4
+#define DAMP 3
 
 #define DROP_RADIUS 2
 // The higher, the smaller the ripple
@@ -113,6 +134,20 @@
     }
 }
 
+int refraction(int d, int wave) {
+    int* map = loadArrayI32(RSID_REFRACTION_MAP, 0);
+    int i = d;
+    if (i < 0) i = -i;
+    if (i > 512) i = 512;
+    int w = (wave + 0x10000) >> 8;
+    w &= ~(w >> 31);
+    int r = (map[i] * w) >> 3;
+    if (d < 0) {
+        return -r;
+    }
+    return r;
+}
+
 void generateRipples() {
     int rippleMapSize = loadI32(RSID_STATE, RSID_RIPPLE_MAP_SIZE);
     int width = loadI32(RSID_STATE, RSID_MESH_WIDTH);
@@ -135,6 +170,19 @@
             int dx = nextWave - wave;
             int dy = current[b] - wave;
 
+            int offsetx = refraction(dx, wave) >> 16;
+            int u = (width - w) + offsetx;
+            u &= ~(u >> 31);
+            if (u >= width) u = width - 1;
+
+            int offsety = refraction(dy, wave) >> 16;
+            int v = (height - h) + offsety;
+            v &= ~(v >> 31);
+            if (v >= height) v = height - 1;
+
+            vertices[(offset + w) * 8 + 3] = u / (float) width;
+            vertices[(offset + w) * 8 + 4] = v / (float) height;
+
             // Update Z coordinate of the vertex
             vertices[(offset + w) * 8 + 7] = (dy / 512.0f) / RIPPLE_HEIGHT;
             
@@ -187,15 +235,210 @@
             n3x /= len;
             n3y /= len;
             n3z /= len;
+            
+            // V2
+            v2x = vertices[(yOffset + width + x + 1) * 8 + 5];
+            v2y = vertices[(yOffset + width + x + 1) * 8 + 6];
+            v2z = vertices[(yOffset + width + x + 1) * 8 + 7];
 
-            vertices[(yOffset + x) * 8 + 0] = -n3x;
-            vertices[(yOffset + x) * 8 + 1] = -n3y;
+            // N1
+            n1x = v2x - v1x;
+            n1y = v2y - v1y;
+            n1z = v2z - v1z;
+
+            // N2
+            n2x = v3x - v1x;
+            n2y = v3y - v1y;
+            n2z = v3z - v1z;
+
+            // Avegare of previous normal and N1 x N2
+            n3x = n3x / 2.0f + (n1y * n2z - n1z * n2y) / 2.0f;
+            n3y = n3y / 2.0f + (n1z * n2x - n1x * n2z) / 2.0f;
+            n3z = n3z / 2.0f + (n1x * n2y - n1y * n2x) / 2.0f;
+
+            // Normalize
+            len = magf3(n3x, n3y, n3z);
+            n3x /= len;
+            n3y /= len;
+            n3z /= len;
+
+            vertices[(yOffset + x) * 8 + 0] = n3x;
+            vertices[(yOffset + x) * 8 + 1] = n3y;
             vertices[(yOffset + x) * 8 + 2] = -n3z;
+            
+            // reset Z
+            //vertices[(yOffset + x) * 8 + 7] = 0.0f;
         }
     }
-}   
+}
+
+void drawNormals() {
+    int width = loadI32(RSID_STATE, RSID_MESH_WIDTH);
+    int height = loadI32(RSID_STATE, RSID_MESH_HEIGHT);
+
+    float *vertices = loadTriangleMeshVerticesF(NAMED_mesh);
+
+    bindProgramVertex(NAMED_PVLines);
+    color(1.0f, 0.0f, 0.0f, 1.0f);
+
+    int y = 0;
+    for ( ; y < height; y++) {
+        int yOffset = y * width;
+        int x = 0;
+        for ( ; x < width; x++) {
+            int offset = (yOffset + x) * 8;
+            float vx = vertices[offset + 5];
+            float vy = vertices[offset + 6];
+            float vz = vertices[offset + 7];
+            float nx = vertices[offset + 0];
+            float ny = vertices[offset + 1];
+            float nz = vertices[offset + 2];
+            drawLine(vx, vy, vz, vx + nx / 10.0f, vy + ny / 10.0f, vz + nz / 10.0f);
+        }
+    }
+}
+
+float averageZ(float x1, float x2, float y1, float y2, float* vertices,
+        int meshWidth, int meshHeight, float glWidth, float glHeight) {
+
+    x1 = ((x1 + glWidth / 2.0f) / glWidth) * meshWidth;
+    x2 = ((x2 + glWidth / 2.0f) / glWidth) * meshWidth;
+    y1 = ((y1 + glHeight / 2.0f) / glHeight) * meshHeight;
+    y2 = ((y2 + glHeight / 2.0f) / glHeight) * meshHeight;
+
+    int quadX1 = clamp(x1, 0, meshWidth);
+    int quadX2 = clamp(x2, 0, meshWidth);
+    int quadY1 = clamp(y1, 0, meshHeight);
+    int quadY2 = clamp(y2, 0, meshHeight);
+
+    float z = 0.0f;
+    int vertexCount = 0;
+
+    int y = quadY1;
+    for ( ; y < quadY2; y++) {
+        int x = quadX1;
+        int yOffset = y * meshWidth;
+        for ( ; x < quadX2; x++) {
+            z += vertices[(yOffset + x) * 8 + 7];
+            vertexCount++;
+        }
+    }
+
+    return 75.0f * z / vertexCount;
+}
+
+void drawLeaf(int index, int frameCount, float* vertices, int meshWidth, int meshHeight,
+        float glWidth, float glHeight) {
+
+    float *leafStruct = loadArrayF(RSID_LEAVES, index);
+
+    float x = leafStruct[LEAF_STRUCT_X];
+    float x1 = x - LEAF_SIZE;
+    float x2 = x + LEAF_SIZE;
+
+    float y = leafStruct[LEAF_STRUCT_Y];
+    float y1 = y - LEAF_SIZE;
+    float y2 = y + LEAF_SIZE;
+
+    float u1 = leafStruct[LEAF_STRUCT_U1];
+    float u2 = leafStruct[LEAF_STRUCT_U2];
+
+    float z1 = 0.0f;
+    float z2 = 0.0f;
+    float z3 = 0.0f;
+    float z4 = 0.0f;
+    
+    float a = leafStruct[LEAF_STRUCT_ALTITUDE];
+    float s = leafStruct[LEAF_STRUCT_SCALE];
+    float r = leafStruct[LEAF_STRUCT_ANGLE];
+
+    float tz = 0.0f;
+    if (a > 0.0f) {
+        tz = -a;
+    } else {
+        z1 = averageZ(x1, x, y1, y, vertices, meshWidth, meshHeight, glWidth, glHeight);
+        z2 = averageZ(x, x2, y1, y, vertices, meshWidth, meshHeight, glWidth, glHeight);
+        z3 = averageZ(x, x2, y, y2, vertices, meshWidth, meshHeight, glWidth, glHeight);
+        z4 = averageZ(x1, x, y, y2, vertices, meshWidth, meshHeight, glWidth, glHeight);
+    }
+
+    x1 -= x;
+    x2 -= x;
+    y1 -= y;
+    y2 -= y;
+
+    float matrix[16];
+    matrixLoadIdentity(matrix);
+    matrixTranslate(matrix, x, y, tz);
+    matrixScale(matrix, s, s, 1.0f);
+    matrixRotate(matrix, r, 0.0f, 0.0f, 1.0f);
+    vpLoadModelMatrix(matrix);
+
+    drawQuadTexCoords(x1, y1, z1, u1, 1.0f,
+                      x2, y1, z2, u2, 1.0f,
+                      x2, y2, z3, u2, 0.0f,
+                      x1, y2, z4, u1, 0.0f);
+
+    float spin = leafStruct[LEAF_STRUCT_SPIN];
+    if (a <= 0.0f) {
+        float rippled = leafStruct[LEAF_STRUCT_RIPPLED];
+        if (rippled < 0.0f) {
+            drop(((x + glWidth / 2.0f) / glWidth) * meshWidth,
+                 meshHeight - ((y + glHeight / 2.0f) / glHeight) * meshHeight,
+                 DROP_RADIUS);
+            spin /= 4.0f;
+            leafStruct[LEAF_STRUCT_SPIN] = spin;
+            leafStruct[LEAF_STRUCT_RIPPLED] = 1.0f;
+        }
+        leafStruct[LEAF_STRUCT_X] = x + leafStruct[LEAF_STRUCT_DELTAX];
+        leafStruct[LEAF_STRUCT_Y] = y + leafStruct[LEAF_STRUCT_DELTAY];
+        r += spin;
+        leafStruct[LEAF_STRUCT_ANGLE] = r;
+    } else {
+        a -= 0.005f;
+        leafStruct[LEAF_STRUCT_ALTITUDE] = a;
+        r += spin * 2.0f;
+        leafStruct[LEAF_STRUCT_ANGLE] = r;
+    }
+
+    if (-LEAF_SIZE * s + x > glWidth / 2.0f || LEAF_SIZE * s + x < -glWidth / 2.0f ||
+        LEAF_SIZE * s + y < -glHeight / 2.0f) {
+
+        int sprite = randf(LEAVES_TEXTURES_COUNT);
+        leafStruct[LEAF_STRUCT_X] = randf2(-1.0f, 1.0f);   
+        leafStruct[LEAF_STRUCT_Y] = glHeight / 2.0f + LEAF_SIZE * 2 * randf(1.0f);
+        leafStruct[LEAF_STRUCT_SCALE] = randf2(0.4f, 0.5f);
+        leafStruct[LEAF_STRUCT_SPIN] = degf(randf2(-0.02f, 0.02f)) / 4.0f;
+        leafStruct[LEAF_STRUCT_U1] = sprite / (float) LEAVES_TEXTURES_COUNT;
+        leafStruct[LEAF_STRUCT_U2] = (sprite + 1) / (float) LEAVES_TEXTURES_COUNT;
+        leafStruct[LEAF_STRUCT_DELTAX] = randf2(-0.02f, 0.02f) / 100.0f;
+        leafStruct[LEAF_STRUCT_DELTAY] = -0.08f * randf2(0.9f, 1.1f) / 100.0f;
+    }
+}
+
+void drawLeaves(int frameCount) {
+    bindProgramFragment(NAMED_PFLeaf);
+    bindProgramFragmentStore(NAMED_PFSLeaf);
+    bindTexture(NAMED_PFLeaf, 0, NAMED_TLeaves);
+
+    int leavesCount = loadI32(RSID_STATE, RSID_LEAVES_COUNT);
+    int count = leavesCount * LEAF_STRUCT_FIELDS_COUNT;
+    int width = loadI32(RSID_STATE, RSID_MESH_WIDTH);
+    int height = loadI32(RSID_STATE, RSID_MESH_HEIGHT);    
+    float glWidth = loadF(RSID_GL_STATE, RSID_GL_WIDTH);
+    float glHeight = loadF(RSID_GL_STATE, RSID_GL_HEIGHT);
+
+    float *vertices = loadTriangleMeshVerticesF(NAMED_mesh);    
+
+    int i = 0;
+    for ( ; i < count; i += LEAF_STRUCT_FIELDS_COUNT) {
+        drawLeaf(i, frameCount, vertices, width, height, glWidth, glHeight);
+    }
+}
 
 int main(int index) {
+    int frameCount = loadI32(RSID_STATE, RSID_FRAME_COUNT);
+
     int dropX = loadI32(RSID_STATE, RSID_DROP_X);
     if (dropX != -1) {
         int dropY = loadI32(RSID_STATE, RSID_DROP_Y);
@@ -204,13 +447,35 @@
         storeI32(RSID_STATE, RSID_DROP_Y, -1);
     }
 
-    updateRipples();
-    generateRipples();
-    updateTriangleMesh(NAMED_mesh);
+    int isRunning = loadI32(RSID_STATE, RSID_RUNNING);
+    if (isRunning) {
+        updateRipples();
+        generateRipples();
+        updateTriangleMesh(NAMED_mesh);
+    }
 
-    ambient(0.0f, 0.1f, 0.9f, 1.0f);
-    diffuse(0.0f, 0.1f, 0.9f, 1.0f);
-    drawTriangleMesh(NAMED_mesh);    
+    float matrix[16];
+    matrixLoadIdentity(matrix);
+    vpLoadModelMatrix(matrix);
+
+    bindTexture(NAMED_PFBackground, 0, NAMED_TRiverbed);
+    drawTriangleMesh(NAMED_mesh);
+
+    ambient(0.0f, 0.0f, 0.0f, 1.0f);
+    diffuse(0.0f, 0.0f, 0.0f, 1.0f);
+    specular(0.44f, 0.44f, 0.44f, 1.0f);
+    shininess(40.0f);
+    bindProgramFragment(NAMED_PFLighting);
+    drawTriangleMesh(NAMED_mesh);
+
+    drawLeaves(frameCount);
+
+    if (!isRunning) {
+        drawNormals();
+    }
+
+    frameCount++;
+    storeI32(RSID_STATE, RSID_FRAME_COUNT, frameCount);
 
     return 1;
 }
diff --git a/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java b/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java
index 542f67c..63e6ed9 100644
--- a/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java
+++ b/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java
@@ -35,6 +35,7 @@
 import static android.renderscript.Element.*;
 import android.graphics.BitmapFactory;
 import android.graphics.Bitmap;
+import static android.util.MathUtils.*;
 
 import java.util.TimeZone;
 
@@ -51,17 +52,43 @@
     private static final int RSID_STATE_RIPPLE_INDEX = 6;
     private static final int RSID_STATE_DROP_X = 7;
     private static final int RSID_STATE_DROP_Y = 8;
+    private static final int RSID_STATE_RUNNING = 9;
+    private static final int RSID_STATE_LEAVES_COUNT = 10;
+
+    private static final int TEXTURES_COUNT = 2;
+    private static final int LEAVES_TEXTURES_COUNT = 4;
+    private static final int RSID_TEXTURE_RIVERBED = 0;
+    private static final int RSID_TEXTURE_LEAVES = 1;
+
+    private static final int RSID_RIPPLE_MAP = 1;
     
-    private static final int RSID_TEXTURES = 1;
-    private static final int TEXTURES_COUNT = 0;
+    private static final int RSID_REFRACTION_MAP = 2;
 
-    private static final int RSID_RIPPLE_MAP = 2;
+    private static final int RSID_LEAVES = 3;
+    private static final int LEAVES_COUNT = 14;
+    private static final int LEAF_STRUCT_FIELDS_COUNT = 11;
+    private static final int LEAF_STRUCT_X = 0;
+    private static final int LEAF_STRUCT_Y = 1;
+    private static final int LEAF_STRUCT_SCALE = 2;
+    private static final int LEAF_STRUCT_ANGLE = 3;
+    private static final int LEAF_STRUCT_SPIN = 4;
+    private static final int LEAF_STRUCT_U1 = 5;
+    private static final int LEAF_STRUCT_U2 = 6;
+    private static final int LEAF_STRUCT_ALTITUDE = 7;
+    private static final int LEAF_STRUCT_RIPPLED = 8;
+    private static final int LEAF_STRUCT_DELTAX = 9;
+    private static final int LEAF_STRUCT_DELTAY = 10;
 
-    private static final int RSID_REFRACTION_MAP = 3;
-
+    private static final int RSID_GL_STATE = 4;    
+    private static final int RSID_STATE_GL_WIDTH = 0;
+    private static final int RSID_STATE_GL_HEIGHT = 1;
+    
+    private boolean mIsRunning = true;    
+    
     private Resources mResources;
     private RenderScript mRS;
-    private final BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
+
+    private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
 
     private final int mWidth;
     private final int mHeight;
@@ -69,14 +96,16 @@
     private ScriptC mScript;
     private Sampler mSampler;
     private ProgramFragment mPfBackground;
+    private ProgramFragment mPfLighting;
+    private ProgramFragment mPfLeaf;
     private ProgramStore mPfsBackground;
+    private ProgramStore mPfsLeaf;
     private ProgramVertex mPvBackground;
+    private ProgramVertex mPvLines;
     private ProgramVertex.MatrixAllocation mPvOrthoAlloc;
     private Light mLight;
 
-    private Allocation mTexturesIDs;
     private Allocation[] mTextures;
-    private int[] mTextureBufferIDs;
 
     private Allocation mState;
     private RenderScript.TriangleMesh mMesh;
@@ -85,12 +114,16 @@
 
     private Allocation mRippleMap;
     private Allocation mRefractionMap;
+    private Allocation mLeaves;
+
+    private Allocation mGlState;
+    private float mGlHeight;
 
     public FallRS(int width, int height) {
         mWidth = width;
         mHeight = height;
-        mBitmapOptions.inScaled = false;
-        mBitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
+        mOptionsARGB.inScaled = false;
+        mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888;
     }
 
     public void init(RenderScript rs, Resources res) {
@@ -106,16 +139,20 @@
         mPfsBackground.destroy();
         mPvBackground.destroy();
         mPvOrthoAlloc.mAlloc.destroy();
-        mTexturesIDs.destroy();
         for (Allocation a : mTextures) {
             a.destroy();
         }
         mState.destroy();
-        mTextureBufferIDs = null;
         mMesh.destroy();
         mLight.destroy();
         mRippleMap.destroy();
         mRefractionMap.destroy();
+        mPvLines.destroy();
+        mPfLighting.destroy();
+        mLeaves.destroy();
+        mPfsLeaf.destroy();
+        mPfLeaf.destroy();
+        mGlState.destroy();
     }
 
     @Override
@@ -143,9 +180,10 @@
         mScript.setTimeZone(TimeZone.getDefault().getID());
 
         mScript.bindAllocation(mState, RSID_STATE);
-        mScript.bindAllocation(mTexturesIDs, RSID_TEXTURES);
         mScript.bindAllocation(mRippleMap, RSID_RIPPLE_MAP);
         mScript.bindAllocation(mRefractionMap, RSID_REFRACTION_MAP);
+        mScript.bindAllocation(mLeaves, RSID_LEAVES);
+        mScript.bindAllocation(mGlState, RSID_GL_STATE);
 
         mRS.contextBindRootScript(mScript);
     }
@@ -168,19 +206,22 @@
             hResolution = MESH_RESOLUTION;
         }
 
-        final float glHeight = 2.0f * height / (float) width;
-        final float quadWidth = 2.0f / (float) wResolution;
-        final float quadHeight = glHeight / (float) hResolution;
+        mGlHeight = 2.0f * height / (float) width;
+        final float glHeight = mGlHeight;
 
+        float quadWidth = 2.0f / (float) wResolution;
+        float quadHeight = glHeight / (float) hResolution;
+        
         wResolution += 2;
         hResolution += 2;        
         
         for (int y = 0; y <= hResolution; y++) {
             final float yOffset = y * quadHeight - glHeight / 2.0f - quadHeight;
+            final float t = 1.0f - y / (float) hResolution;
             for (int x = 0; x <= wResolution; x++) {
                 rs.triangleMeshAddVertex_XYZ_ST_NORM(
                         -1.0f + x * quadWidth - quadWidth, yOffset, 0.0f,
-                        x / (float) wResolution, y / (float) wResolution,
+                        x / (float) wResolution, t,
                         0.0f, 0.0f, -1.0f);
             }
         }
@@ -204,22 +245,23 @@
     private void createScriptStructures() {
         final int rippleMapSize = (mMeshWidth + 2) * (mMeshHeight + 2);
 
-        final int[] data = new int[9];
-        mState = Allocation.createSized(mRS, USER_I32, data.length);
-        data[RSID_STATE_FRAMECOUNT] = 0;
-        data[RSID_STATE_WIDTH] = mWidth;
-        data[RSID_STATE_HEIGHT] = mHeight;
-        data[RSID_STATE_MESH_WIDTH] = mMeshWidth;
-        data[RSID_STATE_MESH_HEIGHT] = mMeshHeight;
-        data[RSID_STATE_RIPPLE_MAP_SIZE] = rippleMapSize;
-        data[RSID_STATE_RIPPLE_INDEX] = 0;
-        data[RSID_STATE_DROP_X] = mMeshWidth / 2;
-        data[RSID_STATE_DROP_Y] = mMeshHeight / 2;
-        mState.data(data);
+        createState(rippleMapSize);
+        createGlState();
+        createRippleMap(rippleMapSize);
+        createRefractionMap();
+        createLeaves();
+    }
 
-        final int[] rippleMap = new int[rippleMapSize * 2];
-        mRippleMap = Allocation.createSized(mRS, USER_I32, rippleMap.length);
+    private void createLeaves() {
+        final float[] leaves = new float[LEAVES_COUNT * LEAF_STRUCT_FIELDS_COUNT];
+        mLeaves = Allocation.createSized(mRS, USER_FLOAT, leaves.length);
+        for (int i = 0; i < leaves.length; i += LEAF_STRUCT_FIELDS_COUNT) {
+            createLeaf(leaves, i);
+        }
+        mLeaves.data(leaves);
+    }
 
+    private void createRefractionMap() {
         final int[] refractionMap = new int[513];
         float ir = 1.0f / 1.333f;
         for (int i = 0; i < refractionMap.length; i++) {
@@ -230,24 +272,64 @@
         mRefractionMap.data(refractionMap);
     }
 
+    private void createRippleMap(int rippleMapSize) {
+        final int[] rippleMap = new int[rippleMapSize * 2];
+        mRippleMap = Allocation.createSized(mRS, USER_I32, rippleMap.length);
+    }
+
+    private void createGlState() {
+        final float[] meshState = new float[2];
+        mGlState = Allocation.createSized(mRS, USER_FLOAT, meshState.length);
+        meshState[RSID_STATE_GL_WIDTH] = 2.0f;
+        meshState[RSID_STATE_GL_HEIGHT] = mGlHeight;
+        mGlState.data(meshState);
+    }
+
+    private void createState(int rippleMapSize) {
+        final int[] data = new int[11];
+        mState = Allocation.createSized(mRS, USER_I32, data.length);
+        data[RSID_STATE_FRAMECOUNT] = 0;
+        data[RSID_STATE_WIDTH] = mWidth;
+        data[RSID_STATE_HEIGHT] = mHeight;
+        data[RSID_STATE_MESH_WIDTH] = mMeshWidth;
+        data[RSID_STATE_MESH_HEIGHT] = mMeshHeight;
+        data[RSID_STATE_RIPPLE_MAP_SIZE] = rippleMapSize;
+        data[RSID_STATE_RIPPLE_INDEX] = 0;
+        data[RSID_STATE_DROP_X] = -1;
+        data[RSID_STATE_DROP_Y] = -1;
+        data[RSID_STATE_RUNNING] = 1;
+        data[RSID_STATE_LEAVES_COUNT] = LEAVES_COUNT;
+        mState.data(data);
+    }
+
+    private void createLeaf(float[] leaves, int index) {
+        int sprite = random(LEAVES_TEXTURES_COUNT);
+        //noinspection PointlessArithmeticExpression
+        leaves[index + LEAF_STRUCT_X] = random(-1.0f, 1.0f);
+        leaves[index + LEAF_STRUCT_Y] = random(-mGlHeight / 2.0f, mGlHeight / 2.0f);
+        leaves[index + LEAF_STRUCT_SCALE] = random(0.4f, 0.5f);
+        leaves[index + LEAF_STRUCT_ANGLE] = random(0.0f, 360.0f);
+        leaves[index + LEAF_STRUCT_SPIN] = degrees(random(-0.02f, 0.02f)) / 4.0f;
+        leaves[index + LEAF_STRUCT_U1] = sprite / (float) LEAVES_TEXTURES_COUNT;
+        leaves[index + LEAF_STRUCT_U2] = (sprite + 1) / (float) LEAVES_TEXTURES_COUNT;
+        leaves[index + LEAF_STRUCT_ALTITUDE] = -1.0f;
+        leaves[index + LEAF_STRUCT_RIPPLED] = 1.0f;
+        leaves[index + LEAF_STRUCT_DELTAX] = random(-0.02f, 0.02f) / 100.0f;
+        leaves[index + LEAF_STRUCT_DELTAY] = -0.08f * random(0.9f, 1.1f) / 100.0f;
+    }
+
     private void loadTextures() {
-        mTextureBufferIDs = new int[TEXTURES_COUNT];
         mTextures = new Allocation[TEXTURES_COUNT];
-        mTexturesIDs = Allocation.createSized(mRS, USER_FLOAT, TEXTURES_COUNT);
 
         final Allocation[] textures = mTextures;
-        // TOOD: Load textures
+        textures[RSID_TEXTURE_RIVERBED] = loadTexture(R.drawable.riverbed, "TRiverbed");
+        textures[RSID_TEXTURE_LEAVES] = loadTextureARGB(R.drawable.leaves, "TLeaves");
 
-        final int[] bufferIds = mTextureBufferIDs;
         final int count = textures.length;
-
         for (int i = 0; i < count; i++) {
             final Allocation texture = textures[i];
             texture.uploadToTexture(0);
-            bufferIds[i] = texture.getID();
         }
-
-        mTexturesIDs.data(bufferIds);
     }
 
     private Allocation loadTexture(int id, String name) {
@@ -258,13 +340,11 @@
     }
 
     private Allocation loadTextureARGB(int id, String name) {
-        // Forces ARGB 32 bits, because pngcrush sometimes optimize our PNGs to
-        // indexed pictures, which are not well supported
-        final Bitmap b = BitmapFactory.decodeResource(mResources, id, mBitmapOptions);
+        Bitmap b = BitmapFactory.decodeResource(mResources, id, mOptionsARGB);
         final Allocation allocation = Allocation.createFromBitmap(mRS, b, RGBA_8888, false);
         allocation.setName(name);
         return allocation;
-    }
+    }    
 
     private void createProgramFragment() {
         Sampler.Builder sampleBuilder = new Sampler.Builder(mRS);
@@ -280,16 +360,37 @@
         mPfBackground = builder.create();
         mPfBackground.setName("PFBackground");
         mPfBackground.bindSampler(mSampler, 0);
+
+        builder = new ProgramFragment.Builder(mRS, null, null);
+        builder.setTexEnable(false, 0);
+        mPfLighting = builder.create();
+        mPfLighting.setName("PFLighting");
+        mPfLighting.bindSampler(mSampler, 0);
+        
+        builder = new ProgramFragment.Builder(mRS, null, null);
+        builder.setTexEnable(true, 0);
+        builder.setTexEnvMode(REPLACE, 0);
+        mPfLeaf = builder.create();
+        mPfLeaf.setName("PFLeaf");
+        mPfLeaf.bindSampler(mSampler, 0);
     }
 
     private void createProgramFragmentStore() {
         ProgramStore.Builder builder = new ProgramStore.Builder(mRS, null, null);
-        builder.setDepthFunc(LESS);
-        builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA);
+        builder.setDepthFunc(ALWAYS);
+        builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE);
         builder.setDitherEnable(true);
         builder.setDepthMask(true);
         mPfsBackground = builder.create();
         mPfsBackground.setName("PFSBackground");
+
+        builder = new ProgramStore.Builder(mRS, null, null);
+        builder.setDepthFunc(ALWAYS);
+        builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA);
+        builder.setDitherEnable(true);
+        builder.setDepthMask(true);
+        mPfsLeaf = builder.create();
+        mPfsLeaf.setName("PFSLeaf");
     }
 
     private void createProgramVertex() {
@@ -297,7 +398,7 @@
         mPvOrthoAlloc.setupProjectionNormalized(mWidth, mHeight);
 
         mLight = new Light.Builder(mRS).create();
-        mLight.setPosition(0.0f, 0.0f, -1.0f);
+        mLight.setPosition(0.0f, 2.0f, -8.0f);
 
         ProgramVertex.Builder builder = new ProgramVertex.Builder(mRS, null, null);
         builder.setTextureMatrixEnable(true);
@@ -305,11 +406,21 @@
         mPvBackground = builder.create();
         mPvBackground.bindAllocation(mPvOrthoAlloc);
         mPvBackground.setName("PVBackground");
+        
+        builder = new ProgramVertex.Builder(mRS, null, null);
+        mPvLines = builder.create();
+        mPvLines.bindAllocation(mPvOrthoAlloc);
+        mPvLines.setName("PVLines");
     }
 
-    public void addDrop(float x, float y) {
+    void addDrop(float x, float y) {
         mState.subData1D(RSID_STATE_DROP_X, 2, new int[] {
                 (int) ((x / mWidth) * mMeshWidth), (int) ((y / mHeight) * mMeshHeight)
         });
     }
+    
+    void togglePause() {
+        mIsRunning = !mIsRunning;
+        mState.subData1D(RSID_STATE_RUNNING, 1, new int[] { mIsRunning ? 1 : 0 });
+    }
 }
diff --git a/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java b/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java
index bb793c8..d7573be 100644
--- a/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java
+++ b/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.view.SurfaceHolder;
 import android.view.MotionEvent;
+import android.view.KeyEvent;
 import android.renderscript.RenderScript;
 import android.renderscript.RSSurfaceView;
 
@@ -28,6 +29,8 @@
 
     public FallView(Context context) {
         super(context);
+        setFocusable(true);
+        setFocusableInTouchMode(true);
     }
 
     public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
@@ -44,6 +47,15 @@
     }
 
     @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER ||
+                keyCode == KeyEvent.KEYCODE_MENU) {
+            mRender.togglePause();
+        }
+        return super.onKeyDown(keyCode, event);
+    }
+
+    @Override
     public boolean onTouchEvent(MotionEvent event) {
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
diff --git a/libs/rs/java/Fountain/res/raw/fountain.c b/libs/rs/java/Fountain/res/raw/fountain.c
index 99551fcd..5ed9ed51 100644
--- a/libs/rs/java/Fountain/res/raw/fountain.c
+++ b/libs/rs/java/Fountain/res/raw/fountain.c
@@ -7,13 +7,13 @@
 
 
 int main(int launchID) {
-    int count, touch, x, y, rate, maxLife, lifeShift;
-    int life;
+    int count, touch, x, y, rate;
     int ct, ct2;
     int newPart;
     int drawCount;
-    int dx, dy, idx;
-    int posx,posy;
+    int idx;
+    float dx, dy;
+    float posx,posy;
     int c;
     int srcIdx;
     int dstIdx;
@@ -24,28 +24,20 @@
     y = loadI32(0, 4);
 
     rate = 4;
-    maxLife = (count / rate) - 1;
-    lifeShift = 0;
-    {
-        life = maxLife;
-        while (life > 255) {
-            life = life >> 1;
-            lifeShift ++;
-        }
-    }
+    int maxLife = (count / rate) - 1;
 
     if (touch) {
         newPart = loadI32(2, 0);
         for (ct2=0; ct2<rate; ct2++) {
-            dx = (int)((randf(1.f) - 0.5f) * 0x10000);
-            dy = (int)((randf(1.f) - 0.5f) * 0x10000);
+            dx = randf(1.f) - 0.5f;
+            dy = randf(1.f) - 0.5f;
 
             idx = newPart * 5 + 1;
-            storeI32(2, idx, dx);
-            storeI32(2, idx + 1, dy);
+            storeF(2, idx, dx);
+            storeF(2, idx + 1, dy);
             storeI32(2, idx + 2, maxLife);
-            storeI32(2, idx + 3, x << 16);
-            storeI32(2, idx + 4, y << 16);
+            storeF(2, idx + 3, x);
+            storeF(2, idx + 4, y);
 
             newPart++;
             if (newPart >= count) {
@@ -56,51 +48,54 @@
     }
 
     drawCount = 0;
+    float height = getHeight();
     for (ct=0; ct < count; ct++) {
         srcIdx = ct * 5 + 1;
 
-        dx = loadI32(2, srcIdx);
-        dy = loadI32(2, srcIdx + 1);
-        life = loadI32(2, srcIdx + 2);
-        posx = loadI32(2, srcIdx + 3);
-        posy = loadI32(2, srcIdx + 4);
+        dx = loadF(2, srcIdx);
+        dy = loadF(2, srcIdx + 1);
+        int life = loadI32(2, srcIdx + 2);
+        posx = loadF(2, srcIdx + 3);
+        posy = loadF(2, srcIdx + 4);
 
         if (life) {
-            if (posy < (480 << 16)) {
+            if (posy < height) {
                 dstIdx = drawCount * 9;
-                c = 0xffafcf | ((life >> lifeShift) << 24);
+                c = 0xcfcfcfcf;
 
                 storeI32(1, dstIdx, c);
-                storeI32(1, dstIdx + 1, posx);
-                storeI32(1, dstIdx + 2, posy);
+                storeF(1, dstIdx + 1, posx);
+                storeF(1, dstIdx + 2, posy);
 
                 storeI32(1, dstIdx + 3, c);
-                storeI32(1, dstIdx + 4, posx + 0x10000);
-                storeI32(1, dstIdx + 5, posy + dy * 4);
+                storeF(1, dstIdx + 4, posx + 1.f);
+                storeF(1, dstIdx + 5, posy + dy);
 
                 storeI32(1, dstIdx + 6, c);
-                storeI32(1, dstIdx + 7, posx - 0x10000);
-                storeI32(1, dstIdx + 8, posy + dy * 4);
+                storeF(1, dstIdx + 7, posx - 1.f);
+                storeF(1, dstIdx + 8, posy + dy);
                 drawCount ++;
             } else {
                 if (dy > 0) {
-                    dy = (-dy) >> 1;
+                    dy *= -0.5f;
                 }
             }
 
             posx = posx + dx;
             posy = posy + dy;
-            dy = dy + 0x400;
+            dy = dy + 0.05f;
             life --;
 
             //storeI32(2, srcIdx, dx);
-            storeI32(2, srcIdx + 1, dy);
+            storeF(2, srcIdx + 1, dy);
             storeI32(2, srcIdx + 2, life);
-            storeI32(2, srcIdx + 3, posx);
-            storeI32(2, srcIdx + 4, posy);
+            storeF(2, srcIdx + 3, posx);
+            storeF(2, srcIdx + 4, posy);
         }
     }
 
-    drawTriangleArray(NAMED_PartBuffer, drawCount);
+    //drawTriangleArray(NAMED_PartBuffer, drawCount);
+    uploadToBufferObject(NAMED_PartBuffer);
+    drawSimpleMeshRange(NAMED_PartMesh, 0, drawCount * 3);
     return 1;
 }
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
index 4826879..ad4f949 100644
--- a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
@@ -33,8 +33,13 @@
 import android.renderscript.ScriptC;
 import android.renderscript.ProgramFragment;
 import android.renderscript.ProgramStore;
+import android.renderscript.SimpleMesh;
+import android.renderscript.Type;
+import android.renderscript.Primitive;
+
 
 public class FountainRS {
+    public static final int PART_COUNT = 4000;
 
     public FountainRS() {
     }
@@ -64,18 +69,15 @@
     private Script mScript;
     private ProgramStore mPFS;
     private ProgramFragment mPF;
+    private SimpleMesh mSM;
 
     private Bitmap mBackground;
 
     int mParams[] = new int[10];
 
     private void initRS() {
-        int partCount = 1024;
-
         mIntAlloc = Allocation.createSized(mRS, Element.USER_I32, 10);
-        mPartAlloc = Allocation.createSized(mRS, Element.USER_I32, partCount * 3 * 3);
-        mPartAlloc.setName("PartBuffer");
-        mVertAlloc = Allocation.createSized(mRS, Element.USER_I32, partCount * 5 + 1);
+        mVertAlloc = Allocation.createSized(mRS, Element.USER_I32, PART_COUNT * 5 + 1);
 
         ProgramStore.Builder bs = new ProgramStore.Builder(mRS, null, null);
         bs.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA, ProgramStore.BlendDstFunc.ONE);
@@ -90,18 +92,35 @@
         mPF.setName("PgmFragParts");
 
         mParams[0] = 0;
-        mParams[1] = partCount;
+        mParams[1] = PART_COUNT;
         mParams[2] = 0;
         mParams[3] = 0;
         mParams[4] = 0;
+        mParams[5] = 0;
+        mParams[6] = 0;
         mIntAlloc.data(mParams);
 
-        int t2[] = new int[partCount * 4*3];
-        for (int ct=0; ct < t2.length; ct++) {
-            t2[ct] = 0;
-        }
-        mPartAlloc.data(t2);
+        Element.Builder eb = new Element.Builder(mRS);
+        eb.add(Element.DataType.UNSIGNED, Element.DataKind.RED, true, 8);
+        eb.add(Element.DataType.UNSIGNED, Element.DataKind.GREEN, true, 8);
+        eb.add(Element.DataType.UNSIGNED, Element.DataKind.BLUE, true, 8);
+        eb.add(Element.DataType.UNSIGNED, Element.DataKind.ALPHA, true, 8);
+        eb.add(Element.DataType.FLOAT, Element.DataKind.X, false, 32);
+        eb.add(Element.DataType.FLOAT, Element.DataKind.Y, false, 32);
+        Element primElement = eb.create();
 
+        SimpleMesh.Builder smb = new SimpleMesh.Builder(mRS);
+        int vtxSlot = smb.addVertexType(primElement, PART_COUNT * 3);
+        smb.setPrimitive(Primitive.TRIANGLE);
+        mSM = smb.create();
+        mSM.setName("PartMesh");
+
+        mPartAlloc = mSM.createVertexAllocation(vtxSlot);
+        mPartAlloc.setName("PartBuffer");
+        mSM.bindVertexAllocation(mPartAlloc, 0);
+
+        // All setup of named objects should be done by this point
+        // because we are about to compile the script.
         ScriptC.Builder sb = new ScriptC.Builder(mRS);
         sb.setScript(mRes, R.raw.fountain);
         sb.setRoot(true);
diff --git a/libs/rs/java/Grass/res/raw/grass.c b/libs/rs/java/Grass/res/raw/grass.c
index 59c6d9a..1490012 100644
--- a/libs/rs/java/Grass/res/raw/grass.c
+++ b/libs/rs/java/Grass/res/raw/grass.c
@@ -23,14 +23,7 @@
 #define RSID_WIDTH 2
 #define RSID_HEIGHT 3
 
-#define RSID_TEXTURES 1
-#define RSID_SKY_TEXTURE_NIGHT 0
-#define RSID_SKY_TEXTURE_SUNRISE 1
-#define RSID_SKY_TEXTURE_NOON 2
-#define RSID_SKY_TEXTURE_SUNSET 3
-#define RSID_GRASS_TEXTURE 4
-
-#define RSID_BLADES 2
+#define RSID_BLADES 1
 #define BLADE_STRUCT_FIELDS_COUNT 12
 #define BLADE_STRUCT_ANGLE 0
 #define BLADE_STRUCT_SIZE 1
diff --git a/libs/rs/java/Grass/src/com/android/grass/rs/GrassRS.java b/libs/rs/java/Grass/src/com/android/grass/rs/GrassRS.java
index 6c17967..7af600f 100644
--- a/libs/rs/java/Grass/src/com/android/grass/rs/GrassRS.java
+++ b/libs/rs/java/Grass/src/com/android/grass/rs/GrassRS.java
@@ -43,10 +43,9 @@
     private static final int RSID_STATE_WIDTH = 2;
     private static final int RSID_STATE_HEIGHT = 3;
 
-    private static final int RSID_TEXTURES = 1;
     private static final int TEXTURES_COUNT = 5;
 
-    private static final int RSID_BLADES = 2;
+    private static final int RSID_BLADES = 1;
     private static final int BLADES_COUNT = 100;
     private static final int BLADE_STRUCT_FIELDS_COUNT = 12;
     private static final int BLADE_STRUCT_ANGLE = 0;
@@ -75,9 +74,7 @@
     private ProgramVertex mPvBackground;
     private ProgramVertex.MatrixAllocation mPvOrthoAlloc;
 
-    private Allocation mTexturesIDs;
     private Allocation[] mTextures;
-    private int[] mTextureBufferIDs;
 
     private Allocation mState;
     private Allocation mBlades;
@@ -100,13 +97,11 @@
         mPfsBackground.destroy();
         mPvBackground.destroy();
         mPvOrthoAlloc.mAlloc.destroy();
-        mTexturesIDs.destroy();
         for (Allocation a : mTextures) {
             a.destroy();
         }
         mState.destroy();
         mBlades.destroy();
-        mTextureBufferIDs = null;
     }
 
     @Override
@@ -133,7 +128,6 @@
         mScript.setTimeZone(TimeZone.getDefault().getID());
 
         mScript.bindAllocation(mState, RSID_STATE);
-        mScript.bindAllocation(mTexturesIDs, RSID_TEXTURES);
         mScript.bindAllocation(mBlades, RSID_BLADES);
 
         mRS.contextBindRootScript(mScript);
@@ -173,9 +167,7 @@
     }
 
     private void loadTextures() {
-        mTextureBufferIDs = new int[TEXTURES_COUNT];
         mTextures = new Allocation[TEXTURES_COUNT];
-        mTexturesIDs = Allocation.createSized(mRS, USER_FLOAT, TEXTURES_COUNT);
 
         final Allocation[] textures = mTextures;
         textures[0] = loadTexture(R.drawable.night, "TNight");
@@ -184,16 +176,11 @@
         textures[3] = loadTexture(R.drawable.sunset, "TSunset");
         textures[4] = generateTextureAlpha(4, 1, new int[] { 0x00FFFF00 }, "TAa");
 
-        final int[] bufferIds = mTextureBufferIDs;
         final int count = textures.length;
-
         for (int i = 0; i < count; i++) {
             final Allocation texture = textures[i];
             texture.uploadToTexture(0);
-            bufferIds[i] = texture.getID();
         }
-
-        mTexturesIDs.data(bufferIds);
     }
 
     private Allocation generateTextureAlpha(int width, int height, int[] data, String name) {
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 05a8c37..7dbf412 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -16,6 +16,16 @@
 	param RsProgramVertex pgm
 	}
 
+ContextSetDefineF {
+    param const char* name
+    param float value
+    }
+
+ContextSetDefineI32 {
+    param const char* name
+    param int32_t value
+    }
+
 AssignName {
 	param void *obj
 	param const char *name
@@ -145,6 +155,10 @@
 	param const void *data
 	}
 
+AllocationRead {
+	param RsAllocation va
+	param void * data
+	}
 
 Adapter1DCreate {
 	ret RsAdapter1D
@@ -318,6 +332,15 @@
 	ret RsScript
 	}
 
+ScriptCSetDefineF {
+    param const char* name
+    param float value
+    }
+
+ScriptCSetDefineI32 {
+    param const char* name
+    param int32_t value
+    }
 
 ProgramFragmentStoreBegin {
 	param RsElement in
@@ -460,3 +483,32 @@
 	}
 
 
+SimpleMeshCreate {
+	ret RsSimpleMesh
+	param RsAllocation prim
+	param RsAllocation index
+	param RsAllocation *vtx
+	param uint32_t vtxCount
+	param uint32_t primType
+	}
+
+SimpleMeshDestroy {
+	param RsSimpleMesh mesh
+	}
+
+SimpleMeshBindIndex {
+	param RsSimpleMesh mesh
+	param RsAllocation idx
+	}
+
+SimpleMeshBindPrimitive {
+	param RsSimpleMesh mesh
+	param RsAllocation prim
+	}
+
+SimpleMeshBindVertex {
+	param RsSimpleMesh mesh
+	param RsAllocation vtx
+	param uint32_t slot
+	}
+
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index ecfbf83..ad9c739 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -41,11 +41,11 @@
     mBufferID = 0;
 
     mType.set(type);
+    rsAssert(type);
     mPtr = malloc(mType->getSizeBytes());
     if (!mPtr) {
         LOGE("Allocation::Allocation, alloc failure");
     }
-
 }
 
 Allocation::~Allocation()
@@ -114,11 +114,17 @@
     glBindBuffer(GL_ARRAY_BUFFER, 0);
 }
 
+
 void Allocation::data(const void *data)
 {
     memcpy(mPtr, data, mType->getSizeBytes());
 }
 
+void Allocation::read(void *data)
+{
+    memcpy(data, mPtr, mType->getSizeBytes());
+}
+
 void Allocation::subData(uint32_t xoff, uint32_t count, const void *data)
 {
     uint32_t eSize = mType->getElementSizeBytes();
@@ -522,6 +528,12 @@
     rsc->allocationCheck(a);
 }
 
+void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data)
+{
+    Allocation *a = static_cast<Allocation *>(va);
+    a->read(data);
+}
+
 
 }
 }
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
index d0b91fd..00af9ed 100644
--- a/libs/rs/rsAllocation.h
+++ b/libs/rs/rsAllocation.h
@@ -23,7 +23,7 @@
 namespace android {
 namespace renderscript {
 
-    
+
 
 class Allocation : public ObjectBase
 {
@@ -55,11 +55,17 @@
 
     void data(const void *data);
     void subData(uint32_t xoff, uint32_t count, const void *data);
-    void subData(uint32_t xoff, uint32_t yoff, 
+    void subData(uint32_t xoff, uint32_t yoff,
                  uint32_t w, uint32_t h, const void *data);
     void subData(uint32_t xoff, uint32_t yoff, uint32_t zoff,
                  uint32_t w, uint32_t h, uint32_t d, const void *data);
 
+    void read(void *data);
+
+    void enableGLVertexBuffers() const;
+    void setupGLIndexBuffers() const;
+
+
 protected:
     ObjectBaseRef<const Type> mType;
     void * mPtr;
@@ -87,7 +93,6 @@
     // is allowed.
     bool mIsVertexBuffer;
     uint32_t mBufferID;
-
 };
 
 }
diff --git a/libs/rs/rsComponent.cpp b/libs/rs/rsComponent.cpp
index a931811..fde62a0 100644
--- a/libs/rs/rsComponent.cpp
+++ b/libs/rs/rsComponent.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "rsComponent.h"
+#include <GLES/gl.h>
 
 using namespace android;
 using namespace android::renderscript;
@@ -29,7 +30,7 @@
 }
 
 Component::Component(
-    DataKind dk, DataType dt, 
+    DataKind dk, DataType dt,
     bool isNormalized, uint32_t bits)
 {
     mType = dt;
@@ -41,3 +42,37 @@
 Component::~Component()
 {
 }
+
+uint32_t Component::getGLType() const
+{
+    switch(mType) {
+    case RS_TYPE_FLOAT:
+        rsAssert(mBits == 32);
+        return GL_FLOAT;
+    case RS_TYPE_SIGNED:
+        switch(mBits) {
+        case 32:
+            return 0;//GL_INT;
+        case 16:
+            return GL_SHORT;
+        case 8:
+            return GL_BYTE;
+        }
+        break;
+    case RS_TYPE_UNSIGNED:
+        switch(mBits) {
+        case 32:
+            return 0;//GL_UNSIGNED_INT;
+        case 16:
+            return GL_UNSIGNED_SHORT;
+        case 8:
+            return GL_UNSIGNED_BYTE;
+        }
+        break;
+    }
+    //rsAssert(!"Bad type");
+    //LOGE("mType %i, mKind %i, mBits %i, mIsNormalized %i", mType, mKind, mBits, mIsNormalized);
+    return 0;
+}
+
+
diff --git a/libs/rs/rsComponent.h b/libs/rs/rsComponent.h
index e1b0585..9db107f 100644
--- a/libs/rs/rsComponent.h
+++ b/libs/rs/rsComponent.h
@@ -52,6 +52,8 @@
     DataKind getKind() const {return mKind;}
     uint32_t getBits() const {return mBits;}
 
+    uint32_t getGLType() const;
+
 protected:
 
     DataType mType;
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 46bd892..9de23b3 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -331,6 +331,26 @@
     }
 }
 
+void Context::appendVarDefines(String8 *str) const
+{
+    char buf[256];
+    for (size_t ct=0; ct < mInt32Defines.size(); ct++) {
+        str->append("#define ");
+        str->append(mInt32Defines.keyAt(ct));
+        str->append(" ");
+        sprintf(buf, "%i\n", (int)mInt32Defines.valueAt(ct));
+        str->append(buf);
+
+    }
+    for (size_t ct=0; ct < mFloatDefines.size(); ct++) {
+        str->append("#define ");
+        str->append(mFloatDefines.keyAt(ct));
+        str->append(" ");
+        sprintf(buf, "%ff\n", mFloatDefines.valueAt(ct));
+        str->append(buf);
+    }
+}
+
 
 ///////////////////////////////////////////////////////////////////////////////////////////
 //
@@ -381,6 +401,15 @@
     rsc->assignName(ob, name, len);
 }
 
+void rsi_ContextSetDefineF(Context *rsc, const char* name, float value)
+{
+    rsc->addInt32Define(name, value);
+}
+
+void rsi_ContextSetDefineI32(Context *rsc, const char* name, int32_t value)
+{
+    rsc->addFloatDefine(name, value);
+}
 
 }
 }
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 1f8352c..54c555f 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -19,6 +19,8 @@
 
 #include "rsUtils.h"
 
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
 #include <utils/Vector.h>
 #include <ui/Surface.h>
 
@@ -26,6 +28,7 @@
 #include "rsMatrix.h"
 #include "rsAllocation.h"
 #include "rsTriangleMesh.h"
+#include "rsSimpleMesh.h"
 #include "rsMesh.h"
 #include "rsDevice.h"
 #include "rsScriptC.h"
@@ -92,7 +95,7 @@
     void removeName(ObjectBase *obj);
     ObjectBase * lookupName(const char *name) const;
     void appendNameDefines(String8 *str) const;
-
+    void appendVarDefines(String8 *str) const;
 
     ProgramFragment * getDefaultProgramFragment() const {
         return mStateFragment.mDefault.get();
@@ -104,6 +107,17 @@
         return mStateFragmentStore.mDefault.get();
     }
 
+    void addInt32Define(const char* name, int32_t value) {
+        mInt32Defines.add(String8(name), value);
+    }
+
+    void addFloatDefine(const char* name, float value) {
+        mFloatDefines.add(String8(name), value);
+    }
+
+    uint32_t getWidth() const {return mWidth;}
+    uint32_t getHeight() const {return mHeight;}
+
 protected:
     Device *mDev;
 
@@ -142,6 +156,8 @@
     Surface *mWndSurface;
 
     Vector<ObjectBase *> mNames;
+    KeyedVector<String8,int> mInt32Defines;
+    KeyedVector<String8,float> mFloatDefines;
 };
 
 
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
index 069a128..0c5cb18 100644
--- a/libs/rs/rsElement.cpp
+++ b/libs/rs/rsElement.cpp
@@ -348,7 +348,7 @@
 }
 
 /////////////////////////////////////////
-// 
+//
 
 namespace android {
 namespace renderscript {
@@ -378,7 +378,7 @@
         sec->initPredefined();
     }
 
-    if ((predef < 0) || 
+    if ((predef < 0) ||
         (static_cast<uint32_t>(predef) >= sec->mPredefinedList.size())) {
         LOGE("rsElementGetPredefined: Request for bad predefined type");
         // error
@@ -395,14 +395,17 @@
 {
     ElementState * sec = &rsc->mStateElement;
 
+    Component *c = new Component(static_cast<Component::DataKind>(dk),
+                                 static_cast<Component::DataType>(dt),
+                                 isNormalized,
+                                 bits);
+    sec->mComponentBuildList.add(c);
 }
 
 RsElement rsi_ElementCreate(Context *rsc)
 {
     ElementState * sec = &rsc->mStateElement;
-
     Element *se = new Element(sec->mComponentBuildList.size());
-    sec->mAllElements.add(se);
 
     for (size_t ct = 0; ct < se->getComponentCount(); ct++) {
         se->setComponent(ct, sec->mComponentBuildList[ct]);
@@ -415,15 +418,7 @@
 
 void rsi_ElementDestroy(Context *rsc, RsElement vse)
 {
-    ElementState * sec = &rsc->mStateElement;
     Element * se = static_cast<Element *>(vse);
-
-    for (size_t ct = 0; ct < sec->mAllElements.size(); ct++) {
-        if (sec->mAllElements[ct] == se) {
-            sec->mAllElements.removeAt(ct);
-            break;
-        }
-    }
     se->decRef();
 }
 
diff --git a/libs/rs/rsElement.h b/libs/rs/rsElement.h
index ea6fa8f..0918522 100644
--- a/libs/rs/rsElement.h
+++ b/libs/rs/rsElement.h
@@ -39,12 +39,12 @@
 
 
     size_t getSizeBits() const;
-    size_t getSizeBytes() const { 
-        return (getSizeBits() + 7) >> 3; 
+    size_t getSizeBytes() const {
+        return (getSizeBits() + 7) >> 3;
     }
 
     size_t getComponentOffsetBits(uint32_t componentNumber) const;
-    size_t getComponentOffsetBytes(uint32_t componentNumber) const { 
+    size_t getComponentOffsetBytes(uint32_t componentNumber) const {
         return (getComponentOffsetBits(componentNumber) + 7) >> 3;
     }
 
@@ -68,7 +68,6 @@
     ElementState();
     ~ElementState();
 
-    Vector<Element *> mAllElements;
     Vector<Component *> mComponentBuildList;
 
 
@@ -78,7 +77,7 @@
             mElement = NULL;
         }
         Predefined(RsElementPredefined en, Element *e) {
-            mEnum = en; 
+            mEnum = en;
             mElement = e;
         }
         RsElementPredefined mEnum;
@@ -87,7 +86,7 @@
     Vector<Predefined> mPredefinedList;
 
     void initPredefined();
-    
+
 };
 
 
diff --git a/libs/rs/rsObjectBase.cpp b/libs/rs/rsObjectBase.cpp
index 3219c39..6a5b7d8 100644
--- a/libs/rs/rsObjectBase.cpp
+++ b/libs/rs/rsObjectBase.cpp
@@ -27,6 +27,7 @@
 
 ObjectBase::~ObjectBase()
 {
+    //LOGV("~ObjectBase %p  ref %i", this, mRefCount);
     rsAssert(!mRefCount);
 }
 
diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp
index ea507dc..a315658 100644
--- a/libs/rs/rsProgramFragment.cpp
+++ b/libs/rs/rsProgramFragment.cpp
@@ -196,19 +196,12 @@
 {
     ProgramFragment *pf = static_cast<ProgramFragment *>(vpf);
     pf->bindTexture(slot, static_cast<Allocation *>(a));
-    if (pf == rsc->getFragment()) {
-        //pf->setupGL();
-    }
 }
 
 void rsi_ProgramFragmentBindSampler(Context *rsc, RsProgramFragment vpf, uint32_t slot, RsSampler s)
 {
     ProgramFragment *pf = static_cast<ProgramFragment *>(vpf);
     pf->bindSampler(slot, static_cast<Sampler *>(s));
-
-    if (pf == rsc->getFragment()) {
-        //pf->setupGL();
-    }
 }
 
 void rsi_ProgramFragmentSetType(Context *rsc, uint32_t slot, RsType vt)
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index b0b8404..3343db5 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -20,6 +20,7 @@
 
 #include "acc/acc.h"
 #include "utils/String8.h"
+#include "utils/Timers.h"
 
 #include <GLES/gl.h>
 #include <GLES/glext.h>
@@ -62,6 +63,11 @@
         rsc->setVertex(mEnviroment.mVertex.get());
     }
 
+    if (launchIndex == 0) {
+        mEnviroment.mStartTimeMillis
+                = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC));
+    }
+
     bool ret = false;
     tls->mScript = this;
     ret = mProgram.mScript(launchIndex) != 0;
@@ -98,6 +104,8 @@
 
     mAccScript = NULL;
 
+    mInt32Defines.clear();
+    mFloatDefines.clear();
 }
 
 static ACCvoid* symbolLookup(ACCvoid* pContext, const ACCchar* name)
@@ -117,6 +125,8 @@
 
     rsc->appendNameDefines(&tmp);
     appendDecls(&tmp);
+    rsc->appendVarDefines(&tmp);
+    appendVarDefines(&tmp);
     tmp.append("#line 1\n");
 
     const char* scriptSource[] = {tmp.string(), mProgram.mScriptText};
@@ -132,7 +142,6 @@
         ACCsizei len;
         accGetScriptInfoLog(mAccScript, sizeof(buf), &len, buf);
         LOGE(buf);
-
     }
 
     mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
@@ -209,9 +218,31 @@
     } else {
         // Deal with an error.
     }
-
 }
 
+
+void ScriptCState::appendVarDefines(String8 *str)
+{
+    char buf[256];
+    LOGD("appendVarDefines mInt32Defines.size()=%d mFloatDefines.size()=%d\n",
+            mInt32Defines.size(), mFloatDefines.size());
+    for (size_t ct=0; ct < mInt32Defines.size(); ct++) {
+        str->append("#define ");
+        str->append(mInt32Defines.keyAt(ct));
+        str->append(" ");
+        sprintf(buf, "%i\n", (int)mInt32Defines.valueAt(ct));
+        str->append(buf);
+    }
+    for (size_t ct=0; ct < mFloatDefines.size(); ct++) {
+        str->append("#define ");
+        str->append(mFloatDefines.keyAt(ct));
+        str->append(" ");
+        sprintf(buf, "%ff\n", mFloatDefines.valueAt(ct));
+        str->append(buf);
+    }
+}
+
+
 namespace android {
 namespace renderscript {
 
@@ -264,6 +295,18 @@
     return s;
 }
 
+void rsi_ScriptCSetDefineF(Context *rsc, const char* name, float value)
+{
+    ScriptCState *ss = &rsc->mScriptC;
+    ss->mFloatDefines.add(String8(name), value);
+}
+
+void rsi_ScriptCSetDefineI32(Context *rsc, const char* name, int32_t value)
+{
+    ScriptCState *ss = &rsc->mScriptC;
+    ss->mInt32Defines.add(String8(name), value);
+}
+
 }
 }
 
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index 860b4d1..ad0e3ee 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -21,6 +21,8 @@
 
 #include "RenderScriptEnv.h"
 
+#include <utils/KeyedVector.h>
+
 struct ACCscript;
 
 // ---------------------------------------------------------------------------
@@ -70,6 +72,7 @@
 
     void clear();
     void runCompiler(Context *rsc);
+    void appendVarDefines(String8 *str);
 
     struct SymbolTable_t {
         const char * mName;
@@ -80,6 +83,9 @@
     static SymbolTable_t gSyms[];
     static const SymbolTable_t * lookupSymbol(const char *);
     static void appendDecls(String8 *str);
+
+    KeyedVector<String8,int> mInt32Defines;
+    KeyedVector<String8,float> mFloatDefines;
 };
 
 
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index b17121f..4ee112d 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -21,6 +21,7 @@
 
 #include "acc/acc.h"
 #include "utils/String8.h"
+#include "utils/Timers.h"
 
 #include <GLES/gl.h>
 #include <GLES/glext.h>
@@ -89,10 +90,10 @@
     glBindBuffer(GL_ARRAY_BUFFER, tm->mBufferObjects[0]);
     glBufferData(GL_ARRAY_BUFFER, tm->mVertexDataSize, tm->mVertexData, GL_STATIC_DRAW);
     glBindBuffer(GL_ARRAY_BUFFER, 0);
-    
+
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, tm->mIndexDataSize, tm->mIndexData, GL_STATIC_DRAW);
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);    
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 }
 
 static uint32_t SC_loadU32(uint32_t bank, uint32_t offset)
@@ -187,26 +188,36 @@
     return amount < low ? low : (amount > high ? high : amount);
 }
 
+static int SC_clamp(int amount, int low, int high)
+{
+    return amount < low ? low : (amount > high ? high : amount);
+}
+
 static float SC_maxf(float a, float b)
 {
-    return a > b ? a : b; 
+    return a > b ? a : b;
 }
 
 static float SC_minf(float a, float b)
 {
-    return a < b ? a : b; 
+    return a < b ? a : b;
 }
 
 static float SC_sqrf(float v)
 {
-    return v * v; 
+    return v * v;
+}
+
+static int SC_sqr(int v)
+{
+    return v * v;
 }
 
 static float SC_distf2(float x1, float y1, float x2, float y2)
 {
     float x = x2 - x1;
     float y = y2 - y1;
-    return sqrtf(x * x + y * y); 
+    return sqrtf(x * x + y * y);
 }
 
 static float SC_distf3(float x1, float y1, float z1, float x2, float y2, float z2)
@@ -214,7 +225,7 @@
     float x = x2 - x1;
     float y = y2 - y1;
     float z = z2 - z1;
-    return sqrtf(x * x + y * y + z * z); 
+    return sqrtf(x * x + y * y + z * z);
 }
 
 static float SC_magf2(float a, float b)
@@ -229,12 +240,12 @@
 
 static float SC_radf(float degrees)
 {
-    return degrees * DEG_TO_RAD; 
+    return degrees * DEG_TO_RAD;
 }
 
 static float SC_degf(float radians)
 {
-    return radians * RAD_TO_DEG; 
+    return radians * RAD_TO_DEG;
 }
 
 static float SC_lerpf(float start, float stop, float amount)
@@ -256,7 +267,7 @@
 // Time routines
 //////////////////////////////////////////////////////////////////////////////
 
-static uint32_t SC_second()
+static int32_t SC_second()
 {
     GET_TLS();
 
@@ -274,13 +285,13 @@
     }
 }
 
-static uint32_t SC_minute()
+static int32_t SC_minute()
 {
     GET_TLS();
-    
+
     time_t rawtime;
     time(&rawtime);
-    
+
     if (sc->mEnviroment.mTimeZone) {
         struct tm timeinfo;
         localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
@@ -290,15 +301,15 @@
         timeinfo = localtime(&rawtime);
         return timeinfo->tm_min;
     }
-}   
+}
 
-static uint32_t SC_hour()
+static int32_t SC_hour()
 {
     GET_TLS();
-    
+
     time_t rawtime;
     time(&rawtime);
-    
+
     if (sc->mEnviroment.mTimeZone) {
         struct tm timeinfo;
         localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
@@ -310,13 +321,13 @@
     }
 }
 
-static uint32_t SC_day()
+static int32_t SC_day()
 {
     GET_TLS();
-    
+
     time_t rawtime;
     time(&rawtime);
-    
+
     if (sc->mEnviroment.mTimeZone) {
         struct tm timeinfo;
         localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
@@ -326,15 +337,15 @@
         timeinfo = localtime(&rawtime);
         return timeinfo->tm_mday;
     }
-}   
+}
 
-static uint32_t SC_month()
+static int32_t SC_month()
 {
     GET_TLS();
-    
+
     time_t rawtime;
     time(&rawtime);
-    
+
     if (sc->mEnviroment.mTimeZone) {
         struct tm timeinfo;
         localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
@@ -344,15 +355,15 @@
         timeinfo = localtime(&rawtime);
         return timeinfo->tm_mon;
     }
-} 
+}
 
-static uint32_t SC_year()
+static int32_t SC_year()
 {
     GET_TLS();
-    
+
     time_t rawtime;
     time(&rawtime);
-    
+
     if (sc->mEnviroment.mTimeZone) {
         struct tm timeinfo;
         localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
@@ -364,6 +375,24 @@
     }
 }
 
+static int32_t SC_uptimeMillis()
+{
+    return nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC));
+}
+
+static int32_t SC_startTimeMillis()
+{
+    GET_TLS();
+    return sc->mEnviroment.mStartTimeMillis;
+}
+
+static int32_t SC_elapsedTimeMillis()
+{
+    GET_TLS();
+    return nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC))
+            - sc->mEnviroment.mStartTimeMillis;
+}
+
 //////////////////////////////////////////////////////////////////////////////
 // Matrix routines
 //////////////////////////////////////////////////////////////////////////////
@@ -518,36 +547,32 @@
     rsi_TriangleMeshRenderRange(rsc, mesh, start, count);
 }
 
-// Assumes (GL_FIXED) x,y,z (GL_UNSIGNED_BYTE)r,g,b,a
-static void SC_drawTriangleArray(int ialloc, uint32_t count)
+static void SC_drawLine(float x1, float y1, float z1,
+                        float x2, float y2, float z2)
 {
     GET_TLS();
-    RsAllocation alloc = (RsAllocation)ialloc;
-
-    const Allocation *a = (const Allocation *)alloc;
-    const uint32_t *ptr = (const uint32_t *)a->getPtr();
-
     rsc->setupCheck();
 
+    float vtx[] = { x1, y1, z1, x2, y2, z2 };
+
     glBindBuffer(GL_ARRAY_BUFFER, 0);
-    //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
-
     glEnableClientState(GL_VERTEX_ARRAY);
+    glVertexPointer(3, GL_FLOAT, 0, vtx);
+
     glDisableClientState(GL_NORMAL_ARRAY);
-    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-    glEnableClientState(GL_COLOR_ARRAY);
+    glDisableClientState(GL_COLOR_ARRAY);
 
-    glVertexPointer(2, GL_FIXED, 12, ptr + 1);
-    //glTexCoordPointer(2, GL_FIXED, 24, ptr + 1);
-    glColorPointer(4, GL_UNSIGNED_BYTE, 12, ptr);
-
-    glDrawArrays(GL_TRIANGLES, 0, count * 3);
+    glDrawArrays(GL_LINES, 0, 2);
 }
 
-static void SC_drawQuad(float x1, float y1, float z1,
-                        float x2, float y2, float z2,
-                        float x3, float y3, float z3,
-                        float x4, float y4, float z4)
+static void SC_drawQuadTexCoords(float x1, float y1, float z1,
+                                 float u1, float v1,
+                                 float x2, float y2, float z2,
+                                 float u2, float v2,
+                                 float x3, float y3, float z3,
+                                 float u3, float v3,
+                                 float x4, float y4, float z4,
+                                 float u4, float v4)
 {
     GET_TLS();
 
@@ -558,8 +583,7 @@
     //LOGE("%4.2f, %4.2f, %4.2f", x4, y4, z4);
 
     float vtx[] = {x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4};
-    static const float tex[] = {0,1, 1,1, 1,0, 0,0};
-
+    const float tex[] = {u1,v1, u2,v2, u3,v3, u4,v4};
 
     rsc->setupCheck();
 
@@ -585,6 +609,17 @@
     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 }
 
+static void SC_drawQuad(float x1, float y1, float z1,
+                        float x2, float y2, float z2,
+                        float x3, float y3, float z3,
+                        float x4, float y4, float z4)
+{
+    SC_drawQuadTexCoords(x1, y1, z1, 0, 1,
+                         x2, y2, z2, 1, 1,
+                         x3, y3, z3, 1, 0,
+                         x4, y4, z4, 0, 0);
+}
+
 static void SC_drawRect(float x1, float y1,
                         float x2, float y2, float z)
 {
@@ -594,6 +629,23 @@
                 x1, y1, z);
 }
 
+static void SC_drawSimpleMesh(RsSimpleMesh vsm)
+{
+    GET_TLS();
+    SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
+    rsc->setupCheck();
+    sm->render();
+}
+
+static void SC_drawSimpleMeshRange(RsSimpleMesh vsm, uint32_t start, uint32_t len)
+{
+    GET_TLS();
+    SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
+    rsc->setupCheck();
+    sm->renderRange(start, len);
+}
+
+
 //////////////////////////////////////////////////////////////////////////////
 //
 //////////////////////////////////////////////////////////////////////////////
@@ -627,10 +679,9 @@
     glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, params);
 }
 
-static void SC_shininess(float r, float g, float b, float a)
+static void SC_shininess(float s)
 {
-    GLfloat params[] = { r, g, b, a };
-    glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, params);
+    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, s);
 }
 
 static void SC_hsb(float h, float s, float b, float a)
@@ -638,18 +689,18 @@
     float red = 0.0f;
     float green = 0.0f;
     float blue = 0.0f;
-    
+
     float x = h;
     float y = s;
     float z = b;
-    
+
     float hf = (x - (int) x) * 6.0f;
     int ihf = (int) hf;
     float f = hf - ihf;
     float pv = z * (1.0f - y);
     float qv = z * (1.0f - y * f);
     float tv = z * (1.0f - y * (1.0f - f));
-    
+
     switch (ihf) {
         case 0:         // Red is the dominant color
             red = z;
@@ -682,35 +733,22 @@
             blue = qv;
             break;
     }
-    
+
     glColor4f(red, green, blue, a);
 }
 
-/*
-extern "C" void materialDiffuse(float r, float g, float b, float a)
-{
-    float v[] = {r, g, b, a};
-    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, v);
-}
-
-extern "C" void materialSpecular(float r, float g, float b, float a)
-{
-    float v[] = {r, g, b, a};
-    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, v);
-}
-
-extern "C" void materialShininess(float s)
-{
-    glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &s);
-}
-*/
-
 static void SC_uploadToTexture(RsAllocation va, uint32_t baseMipLevel)
 {
     GET_TLS();
     rsi_AllocationUploadToTexture(rsc, va, baseMipLevel);
 }
 
+static void SC_uploadToBufferObject(RsAllocation va)
+{
+    GET_TLS();
+    rsi_AllocationUploadToBufferObject(rsc, va);
+}
+
 static void SC_ClearColor(float r, float g, float b, float a)
 {
     //LOGE("c %f %f %f %f", r, g, b, a);
@@ -731,7 +769,17 @@
     LOGE("%s %i", s, i);
 }
 
+static uint32_t SC_getWidth()
+{
+    GET_TLS();
+    return rsc->getWidth();
+}
 
+static uint32_t SC_getHeight()
+{
+    GET_TLS();
+    return rsc->getHeight();
+}
 
 //////////////////////////////////////////////////////////////////////////////
 // Class implementation
@@ -767,6 +815,12 @@
         "void", "(int)" },
 
     // math
+    { "modf", (void *)&fmod,
+        "float", "(float, float)" },
+    { "abs", (void *)&abs,
+        "int", "(int)" },
+    { "absf", (void *)&fabs,
+        "float", "(float)" },
     { "sinf", (void *)&sinf,
         "float", "(float)" },
     { "cosf", (void *)&cosf,
@@ -799,10 +853,16 @@
         "float", "(float, float)" },
     { "minf", (void *)&SC_minf,
         "float", "(float, float)" },
+    { "sqrt", (void *)&sqrt,
+        "int", "(int)" },
     { "sqrtf", (void *)&sqrtf,
         "float", "(float)" },
+    { "sqr", (void *)&SC_sqr,
+        "int", "(int)" },
     { "sqrf", (void *)&SC_sqrf,
         "float", "(float)" },
+    { "clamp", (void *)&SC_clamp,
+        "int", "(int, int, int)" },
     { "clampf", (void *)&SC_clampf,
         "float", "(float, float, float)" },
     { "distf2", (void *)&SC_distf2,
@@ -847,6 +907,12 @@
         "int", "()" },
     { "year", (void *)&SC_year,
         "int", "()" },
+    { "uptimeMillis", (void*)&SC_uptimeMillis,
+        "int", "()" },      // TODO: use long instead
+    { "startTimeMillis", (void*)&SC_startTimeMillis,
+        "int", "()" },      // TODO: use long instead
+    { "elapsedTimeMillis", (void*)&SC_elapsedTimeMillis,
+        "int", "()" },      // TODO: use long instead
 
     // matrix
     { "matrixLoadIdentity", (void *)&SC_matrixLoadIdentity,
@@ -897,12 +963,18 @@
         "void", "(float x1, float y1, float x2, float y2, float z)" },
     { "drawQuad", (void *)&SC_drawQuad,
         "void", "(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4)" },
-    { "drawTriangleArray", (void *)&SC_drawTriangleArray,
-        "void", "(int ialloc, int count)" },
+    { "drawQuadTexCoords", (void *)&SC_drawQuadTexCoords,
+        "void", "(float x1, float y1, float z1, float u1, float v1, float x2, float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3, float x4, float y4, float z4, float u4, float v4)" },
     { "drawTriangleMesh", (void *)&SC_drawTriangleMesh,
         "void", "(int mesh)" },
     { "drawTriangleMeshRange", (void *)&SC_drawTriangleMeshRange,
         "void", "(int mesh, int start, int count)" },
+    { "drawLine", (void *)&SC_drawLine,
+        "void", "(float x1, float y1, float z1, float x2, float y2, float z2)" },
+    { "drawSimpleMesh", (void *)&SC_drawSimpleMesh,
+        "void", "(int ism)" },
+    { "drawSimpleMeshRange", (void *)&SC_drawSimpleMeshRange,
+        "void", "(int ism, int start, int len)" },
 
 
     // misc
@@ -921,10 +993,18 @@
     { "emission", (void *)&SC_emission,
         "void", "(float, float, float, float)" },
     { "shininess", (void *)&SC_shininess,
-        "void", "(float, float, float, float)" },
+        "void", "(float)" },
 
     { "uploadToTexture", (void *)&SC_uploadToTexture,
         "void", "(int, int)" },
+    { "uploadToBufferObject", (void *)&SC_uploadToBufferObject,
+        "void", "(int)" },
+
+    { "getWidth", (void *)&SC_getWidth,
+        "int", "()" },
+    { "getHeight", (void *)&SC_getHeight,
+        "int", "()" },
+
 
 
     { "debugF", (void *)&SC_debugF,
diff --git a/libs/rs/rsSimpleMesh.cpp b/libs/rs/rsSimpleMesh.cpp
new file mode 100644
index 0000000..08e36ac
--- /dev/null
+++ b/libs/rs/rsSimpleMesh.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+SimpleMesh::SimpleMesh()
+{
+}
+
+SimpleMesh::~SimpleMesh()
+{
+}
+
+void SimpleMesh::render() const
+{
+    if (mPrimitiveType.get()) {
+        renderRange(0, mPrimitiveType->getDimX());
+        return;
+    }
+
+    if (mIndexType.get()) {
+        renderRange(0, mIndexType->getDimX());
+        return;
+    }
+
+    renderRange(0, mVertexTypes[0]->getDimX());
+}
+
+void SimpleMesh::renderRange(uint32_t start, uint32_t len) const
+{
+    if (len < 1) {
+        return;
+    }
+
+    glDisableClientState(GL_VERTEX_ARRAY);
+    glDisableClientState(GL_NORMAL_ARRAY);
+    glDisableClientState(GL_COLOR_ARRAY);
+    for (uint32_t ct=0; ct < RS_MAX_TEXTURE; ct++) {
+        glClientActiveTexture(GL_TEXTURE0 + ct);
+        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+    }
+    glClientActiveTexture(GL_TEXTURE0);
+
+    for (uint32_t ct=0; ct < mVertexTypeCount; ct++) {
+        glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[ct]->getBufferObjectID());
+        mVertexTypes[ct]->enableGLVertexBuffer();
+    }
+
+    if (mIndexType.get()) {
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
+        glDrawElements(mGLPrimitive, len, GL_UNSIGNED_SHORT, (GLvoid *)(start * 2));
+    } else {
+        glDrawArrays(mGLPrimitive, start, len);
+    }
+}
+
+
+
+SimpleMeshContext::SimpleMeshContext()
+{
+}
+
+SimpleMeshContext::~SimpleMeshContext()
+{
+}
+
+
+namespace android {
+namespace renderscript {
+
+
+RsSimpleMesh rsi_SimpleMeshCreate(Context *rsc, RsType prim, RsType idx, RsType *vtx, uint32_t vtxCount, uint32_t primType)
+{
+    SimpleMesh *sm = new SimpleMesh();
+    sm->incRef();
+
+    sm->mIndexType.set((const Type *)idx);
+    sm->mPrimitiveType.set((const Type *)prim);
+
+    sm->mVertexTypeCount = vtxCount;
+    sm->mVertexTypes = new ObjectBaseRef<const Type>[vtxCount];
+    sm->mVertexBuffers = new ObjectBaseRef<Allocation>[vtxCount];
+    for (uint32_t ct=0; ct < vtxCount; ct++) {
+        sm->mVertexTypes[ct].set((const Type *)vtx[ct]);
+    }
+
+    sm->mPrimitive = (RsPrimitive)primType;
+    switch(sm->mPrimitive) {
+    case RS_PRIMITIVE_POINT:          sm->mGLPrimitive = GL_POINTS; break;
+    case RS_PRIMITIVE_LINE:           sm->mGLPrimitive = GL_LINES; break;
+    case RS_PRIMITIVE_LINE_STRIP:     sm->mGLPrimitive = GL_LINE_STRIP; break;
+    case RS_PRIMITIVE_TRIANGLE:       sm->mGLPrimitive = GL_TRIANGLES; break;
+    case RS_PRIMITIVE_TRIANGLE_STRIP: sm->mGLPrimitive = GL_TRIANGLE_STRIP; break;
+    case RS_PRIMITIVE_TRIANGLE_FAN:   sm->mGLPrimitive = GL_TRIANGLE_FAN; break;
+    }
+    return sm;
+}
+
+void rsi_SimpleMeshBindVertex(Context *rsc, RsSimpleMesh mv, RsAllocation va, uint32_t slot)
+{
+    SimpleMesh *sm = static_cast<SimpleMesh *>(mv);
+    rsAssert(slot < sm->mVertexTypeCount);
+
+    sm->mVertexBuffers[slot].set((Allocation *)va);
+}
+
+void rsi_SimpleMeshBindIndex(Context *rsc, RsSimpleMesh mv, RsAllocation va)
+{
+    SimpleMesh *sm = static_cast<SimpleMesh *>(mv);
+    sm->mIndexBuffer.set((Allocation *)va);
+}
+
+void rsi_SimpleMeshBindPrimitive(Context *rsc, RsSimpleMesh mv, RsAllocation va)
+{
+    SimpleMesh *sm = static_cast<SimpleMesh *>(mv);
+    sm->mPrimitiveBuffer.set((Allocation *)va);
+}
+
+void rsi_SimpleMeshDestroy(Context *rsc, RsSimpleMesh vtm)
+{
+    SimpleMesh * tm = static_cast<SimpleMesh *>(vtm);
+    tm->decRef();
+}
+
+
+
+
+}}
+
diff --git a/libs/rs/rsSimpleMesh.h b/libs/rs/rsSimpleMesh.h
new file mode 100644
index 0000000..03b6c2c
--- /dev/null
+++ b/libs/rs/rsSimpleMesh.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_SIMPLE_MESH_H
+#define ANDROID_RS_SIMPLE_MESH_H
+
+
+#include "RenderScript.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+// An element is a group of Components that occupies one cell in a structure.
+class SimpleMesh : public ObjectBase
+{
+public:
+    SimpleMesh();
+    ~SimpleMesh();
+
+    ObjectBaseRef<const Type> mIndexType;
+    ObjectBaseRef<const Type> mPrimitiveType;
+    ObjectBaseRef<const Type> *mVertexTypes;
+    uint32_t mVertexTypeCount;
+
+    ObjectBaseRef<Allocation> mIndexBuffer;
+    ObjectBaseRef<Allocation> mPrimitiveBuffer;
+    ObjectBaseRef<Allocation> *mVertexBuffers;
+
+    RsPrimitive mPrimitive;
+    uint32_t mGLPrimitive;
+
+
+    void render() const;
+    void renderRange(uint32_t start, uint32_t len) const;
+
+
+protected:
+};
+
+class SimpleMeshContext
+{
+public:
+    SimpleMeshContext();
+    ~SimpleMeshContext();
+
+
+};
+
+
+}
+}
+#endif //ANDROID_RS_SIMPLE_MESH_H
+
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
index bbe9720..43c3bda 100644
--- a/libs/rs/rsType.cpp
+++ b/libs/rs/rsType.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "rsContext.h"
+#include <GLES/gl.h>
 
 using namespace android;
 using namespace android::renderscript;
@@ -23,6 +24,7 @@
 {
     mLODs = 0;
     mLODCount = 0;
+    memset(&mGL, 0, sizeof(mGL));
     clear();
 }
 
@@ -102,6 +104,7 @@
     }
     mTotalSizeBytes = offset;
 
+    makeGLComponents();
 }
 
 uint32_t Type::getLODOffset(uint32_t lod, uint32_t x) const
@@ -126,8 +129,155 @@
 }
 
 
+void Type::makeGLComponents()
+{
+    uint32_t texNum = 0;
+    memset(&mGL, 0, sizeof(mGL));
+
+    for (uint32_t ct=0; ct < getElement()->getComponentCount(); ct++) {
+        const Component *c = getElement()->getComponent(ct);
+
+        switch(c->getKind()) {
+        case Component::X:
+            rsAssert(mGL.mVtx.size == 0);
+            mGL.mVtx.size = 1;
+            mGL.mVtx.offset = mElement->getComponentOffsetBytes(ct);
+            mGL.mVtx.type = c->getGLType();
+            break;
+        case Component::Y:
+            rsAssert(mGL.mVtx.size == 1);
+            rsAssert(mGL.mVtx.type == c->getGLType());
+            mGL.mVtx.size = 2;
+            break;
+        case Component::Z:
+            rsAssert(mGL.mVtx.size == 2);
+            rsAssert(mGL.mVtx.type == c->getGLType());
+            mGL.mVtx.size = 3;
+            break;
+        case Component::W:
+            rsAssert(mGL.mVtx.size == 4);
+            rsAssert(mGL.mVtx.type == c->getGLType());
+            mGL.mVtx.size = 4;
+        break;
+
+        case Component::RED:
+            rsAssert(mGL.mColor.size == 0);
+            mGL.mColor.size = 1;
+            mGL.mColor.offset = mElement->getComponentOffsetBytes(ct);
+            mGL.mColor.type = c->getGLType();
+            break;
+        case Component::GREEN:
+            rsAssert(mGL.mColor.size == 1);
+            rsAssert(mGL.mColor.type == c->getGLType());
+            mGL.mColor.size = 2;
+            break;
+        case Component::BLUE:
+            rsAssert(mGL.mColor.size == 2);
+            rsAssert(mGL.mColor.type == c->getGLType());
+            mGL.mColor.size = 3;
+            break;
+        case Component::ALPHA:
+            rsAssert(mGL.mColor.size == 3);
+            rsAssert(mGL.mColor.type == c->getGLType());
+            mGL.mColor.size = 4;
+        break;
+
+        case Component::NX:
+            rsAssert(mGL.mNorm.size == 0);
+            mGL.mNorm.size = 1;
+            mGL.mNorm.offset = mElement->getComponentOffsetBytes(ct);
+            mGL.mNorm.type = c->getGLType();
+        break;
+        case Component::NY:
+            rsAssert(mGL.mNorm.size == 1);
+            rsAssert(mGL.mNorm.type == c->getGLType());
+            mGL.mNorm.size = 2;
+        break;
+        case Component::NZ:
+            rsAssert(mGL.mNorm.size == 2);
+            rsAssert(mGL.mNorm.type == c->getGLType());
+            mGL.mNorm.size = 3;
+        break;
+
+        case Component::S:
+            if (mGL.mTex[texNum].size) {
+                texNum++;
+            }
+            mGL.mTex[texNum].size = 1;
+            mGL.mTex[texNum].offset = mElement->getComponentOffsetBytes(ct);
+            mGL.mTex[texNum].type = c->getGLType();
+        break;
+        case Component::T:
+            rsAssert(mGL.mTex[texNum].size == 1);
+            rsAssert(mGL.mTex[texNum].type == c->getGLType());
+            mGL.mTex[texNum].size = 2;
+        break;
+        case Component::R:
+            rsAssert(mGL.mTex[texNum].size == 2);
+            rsAssert(mGL.mTex[texNum].type == c->getGLType());
+            mGL.mTex[texNum].size = 3;
+        break;
+        case Component::Q:
+            rsAssert(mGL.mTex[texNum].size == 3);
+            rsAssert(mGL.mTex[texNum].type == c->getGLType());
+            mGL.mTex[texNum].size = 4;
+        break;
+
+        default:
+            break;
+        }
+    }
+}
+
+void Type::enableGLVertexBuffer() const
+{
+    // Note: We are only going to enable buffers and never disable them
+    // here.  The reasonis more than one Allocation may be used as a vertex
+    // source.  So we cannot disable arrays that may have been in use by
+    // another allocation.
+
+    uint32_t stride = mElement->getSizeBytes();
+    if (mGL.mVtx.size) {
+        glEnableClientState(GL_VERTEX_ARRAY);
+        glVertexPointer(mGL.mVtx.size,
+                        mGL.mVtx.type,
+                        stride,
+                        (void *)mGL.mVtx.offset);
+    }
+
+    if (mGL.mNorm.size) {
+        glEnableClientState(GL_NORMAL_ARRAY);
+        rsAssert(mGL.mNorm.size == 3);
+        glNormalPointer(mGL.mNorm.size,
+                        stride,
+                        (void *)mGL.mNorm.offset);
+    }
+
+    if (mGL.mColor.size) {
+        glEnableClientState(GL_COLOR_ARRAY);
+        glColorPointer(mGL.mColor.size,
+                       mGL.mColor.type,
+                       stride,
+                       (void *)mGL.mColor.offset);
+    }
+
+    for (uint32_t ct=0; ct < RS_MAX_TEXTURE; ct++) {
+        if (mGL.mTex[ct].size) {
+            glClientActiveTexture(GL_TEXTURE0 + ct);
+            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+            glTexCoordPointer(mGL.mTex[ct].size,
+                              mGL.mTex[ct].type,
+                              stride,
+                              (void *)mGL.mTex[ct].offset);
+        }
+    }
+    glClientActiveTexture(GL_TEXTURE0);
+
+}
+
+
 //////////////////////////////////////////////////
-// 
+//
 namespace android {
 namespace renderscript {
 
@@ -190,6 +340,7 @@
     TypeState * stc = &rsc->mStateType;
 
     Type * st = new Type();
+    st->incRef();
     st->setDimX(stc->mX);
     st->setDimY(stc->mY);
     st->setDimZ(stc->mZ);
@@ -198,23 +349,13 @@
     st->setDimFaces(stc->mFaces);
     st->compute();
 
-    stc->mAllTypes.add(st);
-
     return st;
 }
 
 void rsi_TypeDestroy(Context *rsc, RsType vst)
 {
-    TypeState * stc = &rsc->mStateType;
     Type * st = static_cast<Type *>(vst);
-
-    for (size_t ct = 0; ct < stc->mAllTypes.size(); ct++) {
-        if (stc->mAllTypes[ct] == st) {
-            stc->mAllTypes.removeAt(ct);
-            break;
-        }
-    }
-    delete st;
+    st->decRef();
 }
 
 }
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
index a717893..60d75d7 100644
--- a/libs/rs/rsType.h
+++ b/libs/rs/rsType.h
@@ -23,7 +23,7 @@
 namespace android {
 namespace renderscript {
 
-    
+
 class Type : public ObjectBase
 {
 public:
@@ -67,6 +67,8 @@
     void clear();
     void compute();
 
+    void enableGLVertexBuffer() const;
+
 
 protected:
     struct LOD {
@@ -94,7 +96,7 @@
     bool mDimLOD;
     bool mFaces;
 
-    // A list of array dimensions.  The count is the number of array dimensions and the 
+    // A list of array dimensions.  The count is the number of array dimensions and the
     // sizes is a per array size.
     //Vector<size_t> mDimArraysSizes;
 
@@ -105,6 +107,21 @@
     LOD *mLODs;
     uint32_t mLODCount;
 
+    struct VertexComponent_t {
+        uint32_t offset;
+        uint32_t type;
+        uint32_t size;
+        uint32_t stride;
+    };
+    struct GLState_t {
+        VertexComponent_t mVtx;
+        VertexComponent_t mNorm;
+        VertexComponent_t mColor;
+        VertexComponent_t mTex[RS_MAX_TEXTURE];
+    };
+    GLState_t mGL;
+    void makeGLComponents();
+
 private:
     Type(const Type &);
 };
@@ -115,8 +132,6 @@
     TypeState();
     ~TypeState();
 
-    Vector<Type *> mAllTypes;
-
     size_t mX;
     size_t mY;
     size_t mZ;
@@ -124,8 +139,11 @@
     bool mFaces;
     ObjectBaseRef<const Element> mElement;
 
+    ObjectBaseRef<const Type> mIndexType;
+    ObjectBaseRef<const Type> mPrimitiveType;
+    ObjectBaseRef<const Type> *mVertexTypes;
 
-    
+
 };
 
 
diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c
index a4d659d..7cf6bb6 100644
--- a/libs/rs/rsg_generator.c
+++ b/libs/rs/rsg_generator.c
@@ -1,6 +1,6 @@
 
-
-#include "lex.yy.c"
+#include "spec.h"
+#include <stdio.h>
 
 void printFileHeader(FILE *f)
 {
@@ -45,7 +45,7 @@
             fprintf(f, "double");
         break;
     case 4:
-        fprintf(f, "%s", vt->typename);
+        fprintf(f, "%s", vt->typeName);
         break;
     }
 
@@ -157,7 +157,7 @@
             needFlush += vt->ptrLevel;
             fprintf(f, "    cmd->%s = %s;\n", vt->name, vt->name);
         }
-        if (api->ret.typename[0]) {
+        if (api->ret.typeName[0]) {
             needFlush = 1;
         }
 
@@ -167,7 +167,7 @@
         }
         fprintf(f, "(RS_CMD_ID_%s, size);\n", api->name);
 
-        if (api->ret.typename[0]) {
+        if (api->ret.typeName[0]) {
             fprintf(f, "    return reinterpret_cast<");
             printVarType(f, &api->ret);
             fprintf(f, ">(io->mToCoreRet);\n");
@@ -199,7 +199,7 @@
         //fprintf(f, "    LOGE(\"play command %s\\n\");\n", api->name);
         fprintf(f, "    const RS_CMD_%s *cmd = static_cast<const RS_CMD_%s *>(vp);\n", api->name, api->name);
         fprintf(f, "    ");
-        if (api->ret.typename[0]) {
+        if (api->ret.typeName[0]) {
             fprintf(f, "gIO->mToCoreRet = (intptr_t)");
         }
         fprintf(f, "rsi_%s(con", api->name);
diff --git a/libs/rs/spec.h b/libs/rs/spec.h
new file mode 100644
index 0000000..ba802f7
--- /dev/null
+++ b/libs/rs/spec.h
@@ -0,0 +1,41 @@
+#ifndef SPEC_H
+#define SPEC_H
+
+#include <string.h>
+#include <stdlib.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+extern int num_lines;
+
+typedef struct {
+  int isConst;
+  int type;
+  int bits;
+  int ptrLevel;
+  char name[256];
+  char typeName[256];
+} VarType;
+
+extern VarType *currType;
+
+typedef struct {
+  char name[256];
+  int sync;
+  int paramCount;
+  VarType ret;
+  VarType params[16];
+} ApiEntry;
+
+extern ApiEntry apis[128];
+extern int apiCount;
+
+extern int typeNextState;
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+#endif // SPEC_H
diff --git a/libs/rs/spec.lex b/libs/rs/spec.l
similarity index 87%
rename from libs/rs/spec.lex
rename to libs/rs/spec.l
index 0f8e9ab..62fcb63 100644
--- a/libs/rs/spec.lex
+++ b/libs/rs/spec.l
@@ -9,33 +9,19 @@
 DIGIT    [0-9]
 ID       [a-zA-Z_][a-zA-Z0-9_]*
 
+    #include "spec.h"
 
    int num_lines = 0;
 
-   typedef struct {
-      int isConst;
-      int type;
-      int bits;
-      int ptrLevel;
-      char name[256];
-      char typename[256];
-   } VarType;
-
    VarType *currType = 0;
 
-   typedef struct {
-      char name[256];
-      int sync;
-      int paramCount;
-      VarType ret;
-      VarType params[16];
-   } ApiEntry;
-
    ApiEntry apis[128];
    int apiCount = 0;
 
    int typeNextState;
 
+   extern "C" int yylex();
+
 %%
 
 "/*"         BEGIN(comment);
@@ -141,7 +127,7 @@
 <var_type>{ID} {
     currType->type = 4;
     currType->bits = 32;
-    memcpy(currType->typename, yytext, yyleng);
+    memcpy(currType->typeName, yytext, yyleng);
     BEGIN(typeNextState);
     }
 
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
index 88e76dc..c4a70c8 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -24,6 +24,9 @@
 ifeq ($(TARGET_BOARD_PLATFORM), msm7k)
 	LOCAL_CFLAGS += -DDIM_WITH_TEXTURE
 endif
+ifeq ($(TARGET_BOARD_PLATFORM), qsd8k)
+	LOCAL_CFLAGS += -DDIM_WITH_TEXTURE
+endif
 
 # need "-lrt" on Linux simulator to pick up clock_gettime
 ifeq ($(TARGET_SIMULATOR),true)
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 002a3ab..a479b4c 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -42,28 +42,6 @@
 
 using namespace android;
 
-static __attribute__((noinline))
-const char *egl_strerror(EGLint err)
-{
-    switch (err){
-        case EGL_SUCCESS:           return "EGL_SUCCESS";
-        case EGL_NOT_INITIALIZED:   return "EGL_NOT_INITIALIZED";
-        case EGL_BAD_ACCESS:        return "EGL_BAD_ACCESS";
-        case EGL_BAD_ALLOC:         return "EGL_BAD_ALLOC";
-        case EGL_BAD_ATTRIBUTE:     return "EGL_BAD_ATTRIBUTE";
-        case EGL_BAD_CONFIG:        return "EGL_BAD_CONFIG";
-        case EGL_BAD_CONTEXT:       return "EGL_BAD_CONTEXT";
-        case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
-        case EGL_BAD_DISPLAY:       return "EGL_BAD_DISPLAY";
-        case EGL_BAD_MATCH:         return "EGL_BAD_MATCH";
-        case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
-        case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
-        case EGL_BAD_PARAMETER:     return "EGL_BAD_PARAMETER";
-        case EGL_BAD_SURFACE:       return "EGL_BAD_SURFACE";
-        case EGL_CONTEXT_LOST:      return "EGL_CONTEXT_LOST";
-        default: return "UNKNOWN";
-    }
-}
 
 static __attribute__((noinline))
 void checkGLErrors()
@@ -80,7 +58,7 @@
     // GLESonGL seems to be returning 0 when there is no errors?
     if (error && error != EGL_SUCCESS)
         LOGE("%s error 0x%04x (%s)",
-                token, int(error), egl_strerror(error));
+                token, int(error), EGLUtils::strerror(error));
 }
 
 
@@ -112,28 +90,22 @@
 
 void DisplayHardware::init(uint32_t dpy)
 {
-    hw_module_t const* module;
-
     mNativeWindow = new FramebufferNativeWindow();
+    framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
 
     mOverlayEngine = NULL;
+    hw_module_t const* module;
     if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
         overlay_control_open(module, &mOverlayEngine);
     }
 
-    framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
-
-    PixelFormatInfo fbFormatInfo;
-    getPixelFormatInfo(PixelFormat(fbDev->format), &fbFormatInfo);
-
     // initialize EGL
     const EGLint attribs[] = {
-            EGL_BUFFER_SIZE,    fbFormatInfo.bitsPerPixel,
-            EGL_DEPTH_SIZE,     0,
+            EGL_SURFACE_TYPE,   EGL_WINDOW_BIT,
             EGL_NONE
     };
     EGLint w, h, dummy;
-    EGLint numConfigs=0, n=0;
+    EGLint numConfigs=0;
     EGLSurface surface;
     EGLContext context;
     mFlags = 0;
@@ -146,10 +118,16 @@
     eglGetConfigs(display, NULL, 0, &numConfigs);
 
     EGLConfig config;
-    status_t err = EGLUtils::selectConfigForPixelFormat(
-            display, attribs, fbDev->format, &config);
+    status_t err = EGLUtils::selectConfigForNativeWindow(
+            display, attribs, mNativeWindow.get(), &config);
     LOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
     
+    EGLint r,g,b,a;
+    eglGetConfigAttrib(display, config, EGL_RED_SIZE,   &r);
+    eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
+    eglGetConfigAttrib(display, config, EGL_BLUE_SIZE,  &b);
+    eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
+
     /*
      * Gather EGL extensions
      */
@@ -163,7 +141,8 @@
     LOGI("version   : %s", eglQueryString(display, EGL_VERSION));
     LOGI("extensions: %s", egl_extensions);
     LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
-
+    LOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
+    
 
     if (mNativeWindow->isUpdateOnDemand()) {
         mFlags |= UPDATE_ON_DEMAND;
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 9916158..8c0b40d 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -115,16 +115,6 @@
     if (flags & ISurfaceComposer::eSecure)
         bufferFlags |= Buffer::SECURE;
 
-    /* FIXME we need this code for msm7201A
-    if (bufferFlags & Buffer::GPU) {
-        // FIXME: this is msm7201A specific, as its GPU only supports
-        // BGRA_8888.
-        if (format == PIXEL_FORMAT_RGBA_8888) {
-            format = PIXEL_FORMAT_BGRA_8888;
-        }
-    }
-    */
-
     mSecure = (bufferFlags & Buffer::SECURE) ? true : false;
     mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
     for (int i=0 ; i<2 ; i++) {
@@ -227,7 +217,7 @@
     drawWithOpenGL(clip, mTextures[index]);
 }
 
-sp<SurfaceBuffer> Layer::peekBuffer()
+sp<SurfaceBuffer> Layer::peekBuffer(int usage)
 {
     /*
      * This is called from the client's Surface::lock(), after it locked
@@ -260,7 +250,7 @@
     }
     
     LayerBitmap& layerBitmap(mBuffers[backBufferIndex]);
-    sp<SurfaceBuffer> buffer = layerBitmap.allocate();
+    sp<SurfaceBuffer> buffer = layerBitmap.allocate(usage);
     
     LOGD_IF(DEBUG_RESIZE,
             "Layer::getBuffer(this=%p), index=%d, (%d,%d), (%d,%d)",
@@ -659,12 +649,12 @@
 {
 }
 
-sp<SurfaceBuffer> Layer::SurfaceLayer::getBuffer()
+sp<SurfaceBuffer> Layer::SurfaceLayer::getBuffer(int usage)
 {
     sp<SurfaceBuffer> buffer = 0;
     sp<Layer> owner(getOwner());
     if (owner != 0) {
-        buffer = owner->peekBuffer();
+        buffer = owner->peekBuffer(usage);
     }
     return buffer;
 }
diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h
index 4c13d6e..add5d50 100644
--- a/libs/surfaceflinger/Layer.h
+++ b/libs/surfaceflinger/Layer.h
@@ -101,7 +101,7 @@
 
     status_t resize(int32_t index, uint32_t w, uint32_t h, const char* what);
     Region post(uint32_t* oldState, bool& recomputeVisibleRegions);
-    sp<SurfaceBuffer> peekBuffer();
+    sp<SurfaceBuffer> peekBuffer(int usage);
     void destroy();
     void scheduleBroadcast();
 
@@ -114,7 +114,7 @@
                 ~SurfaceLayer();
 
     private:
-        virtual sp<SurfaceBuffer> getBuffer();
+        virtual sp<SurfaceBuffer> getBuffer(int usage);
 
         sp<Layer> getOwner() const {
             return static_cast<Layer*>(Surface::getOwner().get());
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index fbce73d..419574c 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -759,7 +759,7 @@
     return BnSurface::onTransact(code, data, reply, flags);
 }
 
-sp<SurfaceBuffer> LayerBaseClient::Surface::getBuffer() 
+sp<SurfaceBuffer> LayerBaseClient::Surface::getBuffer(int) 
 {
     return NULL; 
 }
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index 6fb1d1c..65bf55b 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -335,7 +335,7 @@
         sp<LayerBaseClient> getOwner() const;
 
     private:
-        virtual sp<SurfaceBuffer> getBuffer();
+        virtual sp<SurfaceBuffer> getBuffer(int usage);
         virtual status_t registerBuffers(const ISurface::BufferHeap& buffers); 
         virtual void postBuffer(ssize_t offset);
         virtual void unregisterBuffers();
diff --git a/libs/surfaceflinger/LayerBitmap.cpp b/libs/surfaceflinger/LayerBitmap.cpp
index 5221fed..5e74451 100644
--- a/libs/surfaceflinger/LayerBitmap.cpp
+++ b/libs/surfaceflinger/LayerBitmap.cpp
@@ -38,13 +38,14 @@
 // Buffer and implementation of android_native_buffer_t
 // ===========================================================================
 
-Buffer::Buffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
+Buffer::Buffer(uint32_t w, uint32_t h, PixelFormat format,
+        uint32_t reqUsage, uint32_t flags)
     : SurfaceBuffer(), mInitCheck(NO_INIT), mFlags(flags), 
     mVStride(0)
 {
     this->format = format;
     if (w>0 && h>0) {
-        mInitCheck = initSize(w, h);
+        mInitCheck = initSize(w, h, reqUsage);
     }
 }
 
@@ -65,7 +66,7 @@
     return static_cast<android_native_buffer_t*>(const_cast<Buffer*>(this));
 }
 
-status_t Buffer::initSize(uint32_t w, uint32_t h)
+status_t Buffer::initSize(uint32_t w, uint32_t h, uint32_t reqUsage)
 {
     status_t err = NO_ERROR;
 
@@ -88,16 +89,9 @@
         usage = BufferAllocator::USAGE_SW_READ_OFTEN | 
                 BufferAllocator::USAGE_SW_WRITE_OFTEN;
     } else {
-        if (mFlags & Buffer::GPU) {
-            // the client wants to do GL rendering
-            usage = BufferAllocator::USAGE_HW_RENDER |
-                    BufferAllocator::USAGE_HW_TEXTURE;
-        } else {
-            // software rendering-client, h/w composition
-            usage = BufferAllocator::USAGE_SW_READ_OFTEN | 
-                    BufferAllocator::USAGE_SW_WRITE_OFTEN |
-                    BufferAllocator::USAGE_HW_TEXTURE;
-        }
+        // it's allowed to modify the usage flags here, but generally
+        // the requested flags should be honored.
+        usage = reqUsage | BufferAllocator::USAGE_HW_TEXTURE;
     }
 
     err = allocator.alloc(w, h, format, usage, &handle, &stride);
@@ -174,12 +168,12 @@
     return NO_ERROR;
 }
 
-sp<Buffer> LayerBitmap::allocate()
+sp<Buffer> LayerBitmap::allocate(uint32_t reqUsage)
 {
     Mutex::Autolock _l(mLock);
     surface_info_t* info = mInfo;
     mBuffer.clear(); // free buffer before allocating a new one
-    sp<Buffer> buffer = new Buffer(mWidth, mHeight, mFormat, mFlags);
+    sp<Buffer> buffer = new Buffer(mWidth, mHeight, mFormat, reqUsage, mFlags);
     status_t err = buffer->initCheck();
     if (LIKELY(err == NO_ERROR)) {
         info->flags  = surface_info_t::eBufferDirty;
diff --git a/libs/surfaceflinger/LayerBitmap.h b/libs/surfaceflinger/LayerBitmap.h
index 22525ce..48ee553 100644
--- a/libs/surfaceflinger/LayerBitmap.h
+++ b/libs/surfaceflinger/LayerBitmap.h
@@ -58,7 +58,8 @@
     };
 
     // creates w * h buffer
-    Buffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags = 0);
+    Buffer(uint32_t w, uint32_t h, PixelFormat format,
+            uint32_t reqUsage, uint32_t flags = 0);
 
     // return status
     status_t initCheck() const;
@@ -81,7 +82,7 @@
     Buffer& operator = (const Buffer& rhs);
     const Buffer& operator = (const Buffer& rhs) const;
 
-    status_t initSize(uint32_t w, uint32_t h);
+    status_t initSize(uint32_t w, uint32_t h, uint32_t reqUsage);
 
     ssize_t                 mInitCheck;
     uint32_t                mFlags;
@@ -108,7 +109,7 @@
 
     status_t setSize(uint32_t w, uint32_t h);
 
-    sp<Buffer> allocate();
+    sp<Buffer> allocate(uint32_t reqUsage);
     status_t free();
     
     sp<const Buffer>  getBuffer() const { return mBuffer; }
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index 90e7f50..bd6d472f 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -28,6 +28,7 @@
 
 #include <hardware/copybit.h>
 
+#include "BufferAllocator.h"
 #include "LayerBuffer.h"
 #include "SurfaceFlinger.h"
 #include "DisplayHardware/DisplayHardware.h"
@@ -464,7 +465,9 @@
                         mTempBitmap->getWidth() < tmp_w || 
                         mTempBitmap->getHeight() < tmp_h) {
                     mTempBitmap.clear();
-                    mTempBitmap = new android::Buffer(tmp_w, tmp_h, src.img.format);
+                    mTempBitmap = new android::Buffer(
+                            tmp_w, tmp_h, src.img.format,
+                            BufferAllocator::USAGE_HW_2D);
                     err = mTempBitmap->initCheck();
                 }
 
diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp
index 8e9df9c..f613767 100644
--- a/libs/surfaceflinger/LayerDim.cpp
+++ b/libs/surfaceflinger/LayerDim.cpp
@@ -21,6 +21,7 @@
 #include <utils/Errors.h>
 #include <utils/Log.h>
 
+#include "BufferAllocator.h"
 #include "LayerDim.h"
 #include "SurfaceFlinger.h"
 #include "DisplayHardware/DisplayHardware.h"
@@ -68,7 +69,10 @@
 
     if (LIKELY(flags & DisplayHardware::DIRECT_TEXTURE)) {
         // TODO: api to pass the usage flags
-        sp<Buffer> buffer = new Buffer(w, h, PIXEL_FORMAT_RGB_565);
+        sp<Buffer> buffer = new Buffer(w, h, PIXEL_FORMAT_RGB_565,
+                 BufferAllocator::USAGE_SW_WRITE_OFTEN |
+                 BufferAllocator::USAGE_HW_TEXTURE);
+        
         android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
 
         glGenTextures(1, &sTexId);
@@ -92,7 +96,7 @@
 
         // initialize the texture with zeros
         GGLSurface t;
-        buffer->lock(&t, GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN);
+        buffer->lock(&t, GRALLOC_USAGE_SW_WRITE_OFTEN);
         memset(t.data, 0, t.stride * t.height * 2);
         buffer->unlock();
         sUseTexture = true;
diff --git a/libs/ui/EGLUtils.cpp b/libs/ui/EGLUtils.cpp
index 80bfdfd..1663313 100644
--- a/libs/ui/EGLUtils.cpp
+++ b/libs/ui/EGLUtils.cpp
@@ -17,6 +17,7 @@
 
 #define LOG_TAG "EGLUtils"
 
+#include <cutils/log.h>
 #include <utils/Errors.h>
 
 #include <ui/EGLUtils.h>
@@ -29,6 +30,28 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
+const char *EGLUtils::strerror(EGLint err)
+{
+    switch (err){
+        case EGL_SUCCESS:           return "EGL_SUCCESS";
+        case EGL_NOT_INITIALIZED:   return "EGL_NOT_INITIALIZED";
+        case EGL_BAD_ACCESS:        return "EGL_BAD_ACCESS";
+        case EGL_BAD_ALLOC:         return "EGL_BAD_ALLOC";
+        case EGL_BAD_ATTRIBUTE:     return "EGL_BAD_ATTRIBUTE";
+        case EGL_BAD_CONFIG:        return "EGL_BAD_CONFIG";
+        case EGL_BAD_CONTEXT:       return "EGL_BAD_CONTEXT";
+        case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
+        case EGL_BAD_DISPLAY:       return "EGL_BAD_DISPLAY";
+        case EGL_BAD_MATCH:         return "EGL_BAD_MATCH";
+        case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
+        case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
+        case EGL_BAD_PARAMETER:     return "EGL_BAD_PARAMETER";
+        case EGL_BAD_SURFACE:       return "EGL_BAD_SURFACE";
+        case EGL_CONTEXT_LOST:      return "EGL_CONTEXT_LOST";
+        default: return "UNKNOWN";
+    }
+}
+
 status_t EGLUtils::selectConfigForPixelFormat(
         EGLDisplay dpy,
         EGLint const* attrs,
@@ -37,6 +60,9 @@
 {
     EGLint numConfigs = -1, n=0;
 
+    if (!attrs)
+        return BAD_VALUE;
+
     if (outConfig == NULL)
         return BAD_VALUE;
     
@@ -65,12 +91,13 @@
     EGLConfig config = NULL;
     for (i=0 ; i<n ; i++) {
         EGLint r,g,b,a;
-        eglGetConfigAttrib(dpy, configs[i], EGL_RED_SIZE,   &r);
-        eglGetConfigAttrib(dpy, configs[i], EGL_GREEN_SIZE, &g);
-        eglGetConfigAttrib(dpy, configs[i], EGL_BLUE_SIZE,  &b);
-        eglGetConfigAttrib(dpy, configs[i], EGL_ALPHA_SIZE, &a);
+        EGLConfig curr = configs[i];
+        eglGetConfigAttrib(dpy, curr, EGL_RED_SIZE,   &r);
+        eglGetConfigAttrib(dpy, curr, EGL_GREEN_SIZE, &g);
+        eglGetConfigAttrib(dpy, curr, EGL_BLUE_SIZE,  &b);
+        eglGetConfigAttrib(dpy, curr, EGL_ALPHA_SIZE, &a);
         if (fbSzA == a && fbSzR == r && fbSzG == g && fbSzB  == b) {
-            config = configs[i];
+            config = curr;
             break;
         }
     }
@@ -93,6 +120,10 @@
 {
     int err;
     int format;
+    
+    if (!window)
+        return BAD_VALUE;
+    
     if ((err = window->query(window, NATIVE_WINDOW_FORMAT, &format)) < 0) {
         return err;
     }
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 7b85c7f..90b5163 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -25,6 +25,7 @@
 #include <cutils/log.h>
 #include <cutils/atomic.h>
 #include <utils/threads.h>
+#include <utils/RefBase.h>
 
 #include <ui/SurfaceComposerClient.h>
 #include <ui/Rect.h>
@@ -81,10 +82,16 @@
     hw_module_t const* module;
     if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
         int stride;
-        framebuffer_open(module, &fbDev);
-        gralloc_open(module, &grDev);
         int err;
+        err = framebuffer_open(module, &fbDev);
+        LOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
+        
+        err = gralloc_open(module, &grDev);
+        LOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));
 
+        // bail out if we can't initialize the modules
+        if (!fbDev || !grDev)
+            return;
         
         mUpdateOnDemand = (fbDev->setUpdateRect != 0);
         
@@ -125,13 +132,22 @@
     android_native_window_t::lockBuffer = lockBuffer;
     android_native_window_t::queueBuffer = queueBuffer;
     android_native_window_t::query = query;
+    android_native_window_t::perform = perform;
 }
 
-FramebufferNativeWindow::~FramebufferNativeWindow() {
-    grDev->free(grDev, buffers[0]->handle);
-    grDev->free(grDev, buffers[1]->handle);
-    gralloc_close(grDev);
-    framebuffer_close(fbDev);
+FramebufferNativeWindow::~FramebufferNativeWindow() 
+{
+    if (grDev) {
+        if (buffers[0] != NULL)
+            grDev->free(grDev, buffers[0]->handle);
+        if (buffers[1] != NULL)
+            grDev->free(grDev, buffers[1]->handle);
+        gralloc_close(grDev);
+    }
+
+    if (fbDev) {
+        framebuffer_close(fbDev);
+    }
 }
 
 status_t FramebufferNativeWindow::setUpdateRectangle(const Rect& r) 
@@ -216,16 +232,36 @@
             *value = fb->format;
             return NO_ERROR;
     }
+    *value = 0;
     return BAD_VALUE;
 }
 
+int FramebufferNativeWindow::perform(android_native_window_t* window,
+        int operation, ...)
+{
+    switch (operation) {
+        case NATIVE_WINDOW_SET_USAGE:
+            break;
+        default:
+            return NAME_NOT_FOUND;
+    }
+    return NO_ERROR;
+}
+
 // ----------------------------------------------------------------------------
 }; // namespace android
 // ----------------------------------------------------------------------------
 
+using namespace android;
 
 EGLNativeWindowType android_createDisplaySurface(void)
 {
-    return new android::FramebufferNativeWindow();
+    FramebufferNativeWindow* w;
+    w = new FramebufferNativeWindow();
+    if (w->getDevice() == NULL) {
+        // get a ref so it can be destroyed when we exit this block
+        sp<FramebufferNativeWindow> ref(w);
+        return NULL;
+    }
+    return (EGLNativeWindowType)w;
 }
-
diff --git a/libs/ui/ISurface.cpp b/libs/ui/ISurface.cpp
index 9fbae1e..b78e8b5 100644
--- a/libs/ui/ISurface.cpp
+++ b/libs/ui/ISurface.cpp
@@ -71,10 +71,11 @@
     {
     }
 
-    virtual sp<SurfaceBuffer> getBuffer()
+    virtual sp<SurfaceBuffer> getBuffer(int usage)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
+        data.writeInt32(usage);
         remote()->transact(GET_BUFFER, data, &reply);
         sp<SurfaceBuffer> buffer = new SurfaceBuffer(reply);
         return buffer;
@@ -135,7 +136,8 @@
     switch(code) {
         case GET_BUFFER: {
             CHECK_INTERFACE(ISurface, data, reply);
-            sp<SurfaceBuffer> buffer(getBuffer());
+            int usage = data.readInt32();
+            sp<SurfaceBuffer> buffer(getBuffer(usage));
             return SurfaceBuffer::writeToParcel(reply, buffer.get());
         }
         case REGISTER_BUFFERS: {
diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp
index 4abb7f6..2b6905f 100644
--- a/libs/ui/Surface.cpp
+++ b/libs/ui/Surface.cpp
@@ -414,6 +414,7 @@
     android_native_window_t::lockBuffer       = lockBuffer;
     android_native_window_t::queueBuffer      = queueBuffer;
     android_native_window_t::query            = query;
+    android_native_window_t::perform          = perform;
     mSwapRectangle.makeInvalid();
     DisplayInfo dinfo;
     SurfaceComposerClient::getDisplayInfo(0, &dinfo);
@@ -423,6 +424,8 @@
     const_cast<int&>(android_native_window_t::minSwapInterval) = 1;
     const_cast<int&>(android_native_window_t::maxSwapInterval) = 1;
     const_cast<uint32_t&>(android_native_window_t::flags) = 0;
+    // be default we request a hardware surface
+    mUsage = GRALLOC_USAGE_HW_RENDER;
 }
 
 
@@ -512,6 +515,17 @@
     return self->query(what, value);
 }
 
+int Surface::perform(android_native_window_t* window, 
+        int operation, ...)
+{
+    va_list args;
+    va_start(args, operation);
+    Surface* self = getSelf(window);
+    int res = self->perform(operation, args);
+    va_end(args);
+    return res;
+}
+
 // ----------------------------------------------------------------------------
 
 status_t Surface::dequeueBuffer(sp<SurfaceBuffer>* buffer)
@@ -561,7 +575,7 @@
 
     volatile const surface_info_t* const back = lcblk->surface + backIdx;
     if (back->flags & surface_info_t::eNeedNewBuffer) {
-        err = getBufferLocked(backIdx);
+        err = getBufferLocked(backIdx, mUsage);
     }
 
     if (err == NO_ERROR) {
@@ -627,6 +641,20 @@
     return BAD_VALUE;
 }
 
+int Surface::perform(int operation, va_list args)
+{
+    int res = NO_ERROR;
+    switch (operation) {
+        case NATIVE_WINDOW_SET_USAGE:
+            mUsage = va_arg(args, int);
+            break;
+        default:
+            res = NAME_NOT_FOUND;
+            break;
+    }
+    return res;
+}
+
 // ----------------------------------------------------------------------------
 
 status_t Surface::lock(SurfaceInfo* info, bool blocking) {
@@ -636,6 +664,9 @@
 status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking) 
 {
     // FIXME: needs some locking here
+
+    // we're intending to do software rendering from this point
+    mUsage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
     
     sp<SurfaceBuffer> backBuffer;
     status_t err = dequeueBuffer(&backBuffer);
@@ -725,10 +756,10 @@
     mSwapRectangle = r;
 }
 
-status_t Surface::getBufferLocked(int index)
+status_t Surface::getBufferLocked(int index, int usage)
 {
     status_t err = NO_MEMORY;
-    sp<SurfaceBuffer> buffer = mSurface->getBuffer();
+    sp<SurfaceBuffer> buffer = mSurface->getBuffer(usage);
     LOGE_IF(buffer==0, "ISurface::getBuffer() returned NULL");
     if (buffer != 0) {
         sp<SurfaceBuffer>& currentBuffer(mBuffers[index]);
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 645f3f6..6d7c0ae 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -128,7 +128,10 @@
     }
 
     public void setFilename(String filename) {
-        mFilename = filename;
+        if (mFilename == null || !mFilename.equals(filename)) {
+            mFilename = filename;
+            mCachedAttributes = null;
+        }
     }
 
     /**
diff --git a/media/libdrm/mobile2/src/util/domcore/NodeIterator.cpp b/media/libdrm/mobile2/src/util/domcore/NodeIterator.cpp
index f076cda..fe13669 100644
--- a/media/libdrm/mobile2/src/util/domcore/NodeIterator.cpp
+++ b/media/libdrm/mobile2/src/util/domcore/NodeIterator.cpp
@@ -88,7 +88,7 @@
             node = node->getLastChild();

     } else {

         if (node == scopeNode)

-            node == NULL;

+            node = NULL;

         else

             node = node->getParentNode();

     }

diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 4661af6..d1dbc5c 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -6,6 +6,7 @@
 #include <binder/Parcel.h>
 #include <media/IOMX.h>
 #include <ui/ISurface.h>
+#include <ui/Surface.h>
 
 namespace android {
 
@@ -29,6 +30,18 @@
     RENDERER_RENDER,
 };
 
+sp<IOMXRenderer> IOMX::createRenderer(
+        const sp<Surface> &surface,
+        const char *componentName,
+        OMX_COLOR_FORMATTYPE colorFormat,
+        size_t encodedWidth, size_t encodedHeight,
+        size_t displayWidth, size_t displayHeight) {
+    return createRenderer(
+            surface->getISurface(),
+            componentName, colorFormat, encodedWidth, encodedHeight,
+            displayWidth, displayHeight);
+}
+
 static void *readVoidStar(const Parcel *parcel) {
     // FIX if sizeof(void *) != sizeof(int32)
     return (void *)parcel->readInt32();
@@ -45,23 +58,6 @@
         : BpInterface<IOMX>(impl) {
     }
 
-#if IOMX_USES_SOCKETS
-    virtual status_t connect(int *sd) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        remote()->transact(CONNECT, data, &reply);
-
-        status_t err = reply.readInt32();
-        if (err == OK) {
-            *sd = dup(reply.readFileDescriptor());
-        } else {
-            *sd = -1;
-        }
-
-        return reply.readInt32();
-    }
-#endif
-
     virtual status_t list_nodes(List<String8> *list) {
         list->clear();
 
@@ -229,7 +225,6 @@
         return reply.readInt32();
     }
 
-#if !IOMX_USES_SOCKETS
     virtual status_t observe_node(
             node_id node, const sp<IOMXObserver> &observer) {
         Parcel data, reply;
@@ -264,7 +259,6 @@
         data.writeInt64(timestamp);
         remote()->transact(EMPTY_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
     }
-#endif
 
     virtual sp<IOMXRenderer> createRenderer(
             const sp<ISurface> &surface,
@@ -302,28 +296,6 @@
 status_t BnOMX::onTransact(
     uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
     switch (code) {
-#if IOMX_USES_SOCKETS
-        case CONNECT:
-        {
-            CHECK_INTERFACE(IOMX, data, reply);
-
-            int s;
-            status_t err = connect(&s);
-            
-            reply->writeInt32(err);
-            if (err == OK) {
-                assert(s >= 0);
-                reply->writeDupFileDescriptor(s);
-                close(s);
-                s = -1;
-            } else {
-                assert(s == -1);
-            }
-
-            return NO_ERROR;
-        }
-#endif
-
         case LIST_NODES:
         {
             CHECK_INTERFACE(IOMX, data, reply);
@@ -495,7 +467,6 @@
             return NO_ERROR;
         }
 
-#if !IOMX_USES_SOCKETS
         case OBSERVE_NODE:
         {
             CHECK_INTERFACE(IOMX, data, reply);
@@ -536,7 +507,6 @@
 
             return NO_ERROR;
         }
-#endif
 
         case CREATE_RENDERER:
         {
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 3ea64ae..799c349 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -914,7 +914,7 @@
                 }
             }
         } else {
-            mState == TONE_IDLE;
+            mState = TONE_IDLE;
         }
     } else {
         LOGV("Delayed start\n");
diff --git a/media/libstagefright/MediaPlayerImpl.cpp b/media/libstagefright/MediaPlayerImpl.cpp
index 341f002..f2e62f5 100644
--- a/media/libstagefright/MediaPlayerImpl.cpp
+++ b/media/libstagefright/MediaPlayerImpl.cpp
@@ -646,15 +646,21 @@
     success = success && meta->findInt32(kKeyHeight, &decodedHeight);
     assert(success);
 
-    const sp<ISurface> &isurface =
-        mSurface.get() != NULL ? mSurface->getISurface() : mISurface;
-
-    mVideoRenderer =
-        mClient.interface()->createRenderer(
-                isurface, component,
-                (OMX_COLOR_FORMATTYPE)format,
-                decodedWidth, decodedHeight,
-                mVideoWidth, mVideoHeight);
+    if (mSurface.get() != NULL) {
+        mVideoRenderer =
+            mClient.interface()->createRenderer(
+                    mSurface, component,
+                    (OMX_COLOR_FORMATTYPE)format,
+                    decodedWidth, decodedHeight,
+                    mVideoWidth, mVideoHeight);
+    } else {
+        mVideoRenderer =
+            mClient.interface()->createRenderer(
+                    mISurface, component,
+                    (OMX_COLOR_FORMATTYPE)format,
+                    decodedWidth, decodedHeight,
+                    mVideoWidth, mVideoHeight);
+    }
 }
 
 void MediaPlayerImpl::depopulateISurface() {
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index 1bc8a44..3e7cf3c 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -30,8 +30,7 @@
 
 namespace android {
 
-OMXClient::OMXClient()
-    : mSock(-1) {
+OMXClient::OMXClient() {
 }
 
 OMXClient::~OMXClient() {
@@ -41,10 +40,6 @@
 status_t OMXClient::connect() {
     Mutex::Autolock autoLock(mLock);
 
-    if (mSock >= 0) {
-        return UNKNOWN_ERROR;
-    }
-
     sp<IServiceManager> sm = defaultServiceManager();
     sp<IBinder> binder = sm->getService(String16("media.player"));
     sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
@@ -54,152 +49,22 @@
     mOMX = service->createOMX();
     assert(mOMX.get() != NULL);
 
-#if IOMX_USES_SOCKETS
-    status_t result = mOMX->connect(&mSock);
-    if (result != OK) {
-        mSock = -1;
-
-        mOMX = NULL;
-        return result;
-    }
-
-    pthread_attr_t attr;
-    pthread_attr_init(&attr);
-    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
-
-    int err = pthread_create(&mThread, &attr, ThreadWrapper, this);
-    assert(err == 0);
-
-    pthread_attr_destroy(&attr);
-#else
     mReflector = new OMXClientReflector(this);
-#endif
 
     return OK;
 }
 
 void OMXClient::disconnect() {
-    {
-        Mutex::Autolock autoLock(mLock);
+    Mutex::Autolock autoLock(mLock);
 
-        if (mSock < 0) {
-            return;
-        }
-
-        assert(mObservers.isEmpty());
+    if (mReflector.get() != NULL) {
+        return;
     }
 
-#if IOMX_USES_SOCKETS
-    omx_message msg;
-    msg.type = omx_message::DISCONNECT;
-    ssize_t n = send(mSock, &msg, sizeof(msg), 0);
-    assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
+    assert(mObservers.isEmpty());
 
-    void *dummy;
-    pthread_join(mThread, &dummy);
-#else
     mReflector->reset();
     mReflector.clear();
-#endif
-}
-
-#if IOMX_USES_SOCKETS
-// static
-void *OMXClient::ThreadWrapper(void *me) {
-    ((OMXClient *)me)->threadEntry();
-
-    return NULL;
-}
-
-void OMXClient::threadEntry() {
-    bool done = false;
-    while (!done) {
-        omx_message msg;
-        ssize_t n = recv(mSock, &msg, sizeof(msg), 0);
-
-        if (n <= 0) {
-            break;
-        }
-
-        done = onOMXMessage(msg);
-    }
-
-    Mutex::Autolock autoLock(mLock);
-    close(mSock);
-    mSock = -1;
-}
-#endif
-
-status_t OMXClient::fillBuffer(IOMX::node_id node, IOMX::buffer_id buffer) {
-#if !IOMX_USES_SOCKETS
-    mOMX->fill_buffer(node, buffer);
-#else
-    if (mSock < 0) {
-        return UNKNOWN_ERROR;
-    }
-
-    omx_message msg;
-    msg.type = omx_message::FILL_BUFFER;
-    msg.u.buffer_data.node = node;
-    msg.u.buffer_data.buffer = buffer;
-
-    ssize_t n = send(mSock, &msg, sizeof(msg), 0);
-    assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
-#endif
-
-    return OK;
-}
-
-status_t OMXClient::emptyBuffer(
-        IOMX::node_id node, IOMX::buffer_id buffer,
-        OMX_U32 range_offset, OMX_U32 range_length,
-        OMX_U32 flags, OMX_TICKS timestamp) {
-#if !IOMX_USES_SOCKETS
-    mOMX->empty_buffer(
-            node, buffer, range_offset, range_length, flags, timestamp);
-#else
-    if (mSock < 0) {
-        return UNKNOWN_ERROR;
-    }
-
-    // XXX I don't like all this copying...
-
-    omx_message msg;
-    msg.type = omx_message::EMPTY_BUFFER;
-    msg.u.extended_buffer_data.node = node;
-    msg.u.extended_buffer_data.buffer = buffer;
-    msg.u.extended_buffer_data.range_offset = range_offset;
-    msg.u.extended_buffer_data.range_length = range_length;
-    msg.u.extended_buffer_data.flags = flags;
-    msg.u.extended_buffer_data.timestamp = timestamp;
-
-    ssize_t n = send(mSock, &msg, sizeof(msg), 0);
-    assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
-#endif
-
-    return OK;
-}
-
-status_t OMXClient::send_command(
-        IOMX::node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
-#if !IOMX_USES_SOCKETS
-    return mOMX->send_command(node, cmd, param);
-#else
-    if (mSock < 0) {
-        return UNKNOWN_ERROR;
-    }
-
-    omx_message msg;
-    msg.type = omx_message::SEND_COMMAND;
-    msg.u.send_command_data.node = node;
-    msg.u.send_command_data.cmd = cmd;
-    msg.u.send_command_data.param = param;
-
-    ssize_t n = send(mSock, &msg, sizeof(msg), 0);
-    assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
-#endif
-
-    return OK;
 }
 
 status_t OMXClient::registerObserver(
@@ -214,9 +79,7 @@
     mObservers.add(node, observer);
     observer->start();
 
-#if !IOMX_USES_SOCKETS
     mOMX->observe_node(node, mReflector);
-#endif
 
     return OK;
 }
@@ -263,15 +126,6 @@
             break;
         }
 
-#if IOMX_USES_SOCKETS
-        case omx_message::DISCONNECTED:
-        {
-            LOGV("Disconnected");
-            done = true;
-            break;
-        }
-#endif
-
         default:
             LOGE("received unknown omx_message type %d", msg.type);
             break;
diff --git a/media/libstagefright/OMXDecoder.cpp b/media/libstagefright/OMXDecoder.cpp
index c570278..a00872f 100644
--- a/media/libstagefright/OMXDecoder.cpp
+++ b/media/libstagefright/OMXDecoder.cpp
@@ -1041,8 +1041,7 @@
                 IOMX::buffer_id buffer = *obuffers->begin();
                 obuffers->erase(obuffers->begin());
 
-                status_t err = mClient->fillBuffer(mNode, buffer);
-                assert(err == NO_ERROR);
+                mOMX->fill_buffer(mNode, buffer);
             }
 
             break;
@@ -1178,7 +1177,7 @@
 
         LOGV("Executing->Idle complete, initiating Idle->Loaded");
         status_t err =
-            mClient->send_command(mNode, OMX_CommandStateSet, OMX_StateLoaded);
+            mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateLoaded);
         assert(err == NO_ERROR);
 
         freePortBuffers(kPortIndexInput);
@@ -1215,7 +1214,7 @@
         setPortStatus(kPortIndexInput, kPortStatusFlushingToShutdown);
         setPortStatus(kPortIndexOutput, kPortStatusFlushingToShutdown);
     } else {
-        err = mClient->send_command(
+        err = mOMX->send_command(
                 mNode, OMX_CommandStateSet, OMX_StateIdle);
 
         setPortStatus(kPortIndexInput, kPortStatusShutdown);
@@ -1300,14 +1299,14 @@
         default:
         {
             if (msg.type == omx_message::INITIAL_FILL_BUFFER) {
-                err = mClient->fillBuffer(mNode, buffer);
+                mOMX->fill_buffer(mNode, buffer);
             } else {
                 LOGV("[%s] Filled OUTPUT buffer %p, flags=0x%08lx.",
                      mComponentName, buffer, msg.u.extended_buffer_data.flags);
 
                 onRealFillBufferDone(msg);
-                err = NO_ERROR;
             }
+            err = NO_ERROR;
             break;
         }
     }
@@ -1348,13 +1347,11 @@
 
         ++mCodecSpecificDataIterator;
 
-        status_t err = mClient->emptyBuffer(
+        mOMX->empty_buffer(
                 mNode, buffer, 0, range_length, 
                 OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG,
                 0);
 
-        assert(err == NO_ERROR);
-
         return;
     }
 
@@ -1385,10 +1382,9 @@
         }
 
         if (err != OK) {
-            status_t err2 = mClient->emptyBuffer(
+            mOMX->empty_buffer(
                     mNode, buffer, 0, 0, OMX_BUFFERFLAG_EOS, 0);
 
-            assert(err2 == NO_ERROR);
             return;
         }
 
@@ -1452,9 +1448,8 @@
     LOGV("[%s] Calling EmptyBuffer on buffer %p size:%d flags:0x%08lx",
          mComponentName, buffer, src_length, flags);
 
-    status_t err2 = mClient->emptyBuffer(
+    mOMX->empty_buffer(
             mNode, buffer, 0, src_length, flags, timestamp);
-    assert(err2 == OK);
 }
 
 void OMXDecoder::onRealFillBufferDone(const omx_message &msg) {
@@ -1517,8 +1512,7 @@
     } else {
         LOGV("[%s] Calling FillBuffer on buffer %p.", mComponentName, buffer);
 
-        status_t err = mClient->fillBuffer(mNode, buffer);
-        assert(err == NO_ERROR);
+        mOMX->fill_buffer(mNode, buffer);
     }
 }
 
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 062afd4..d44e3a3 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -154,151 +154,9 @@
     return meta->owner()->OnFillBufferDone(meta, pBuffer);
 }
 
-OMX::OMX()
-#if IOMX_USES_SOCKETS
-    : mSock(-1)
-#endif
-{
+OMX::OMX() {
 }
 
-OMX::~OMX() {
-#if IOMX_USES_SOCKETS
-    assert(mSock < 0);
-#endif
-}
-
-#if IOMX_USES_SOCKETS
-status_t OMX::connect(int *sd) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mSock >= 0) {
-        return UNKNOWN_ERROR;
-    }
-
-    int sockets[2];
-    if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets) < 0) {
-        return UNKNOWN_ERROR;
-    }
-
-    mSock = sockets[0];
-    *sd = sockets[1];
-
-    pthread_attr_t attr;
-    pthread_attr_init(&attr);
-    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
-
-    int err = pthread_create(&mThread, &attr, ThreadWrapper, this);
-    assert(err == 0);
-
-    pthread_attr_destroy(&attr);
-
-    return OK;
-}
-
-// static
-void *OMX::ThreadWrapper(void *me) {
-    ((OMX *)me)->threadEntry();
-
-    return NULL;
-}
-
-void OMX::threadEntry() {
-    bool done = false;
-    while (!done) {
-        omx_message msg;
-        ssize_t n = recv(mSock, &msg, sizeof(msg), 0);
-
-        if (n <= 0) {
-            break;
-        }
-
-        Mutex::Autolock autoLock(mLock);
-
-        switch (msg.type) {
-            case omx_message::FILL_BUFFER:
-            {
-                OMX_BUFFERHEADERTYPE *header =
-                    static_cast<OMX_BUFFERHEADERTYPE *>(
-                            msg.u.buffer_data.buffer);
-
-                header->nFilledLen = 0;
-                header->nOffset = 0;
-                header->hMarkTargetComponent = NULL;
-                header->nFlags = 0;
-
-                NodeMeta *node_meta = static_cast<NodeMeta *>(
-                        msg.u.buffer_data.node);
-                
-                LOGV("FillThisBuffer buffer=%p", header);
-
-                OMX_ERRORTYPE err =
-                    OMX_FillThisBuffer(node_meta->handle(), header);
-                assert(err == OMX_ErrorNone);
-                break;
-            }
-
-            case omx_message::EMPTY_BUFFER:
-            {
-                OMX_BUFFERHEADERTYPE *header =
-                    static_cast<OMX_BUFFERHEADERTYPE *>(
-                            msg.u.extended_buffer_data.buffer);
-
-                header->nFilledLen = msg.u.extended_buffer_data.range_length;
-                header->nOffset = msg.u.extended_buffer_data.range_offset;
-                header->hMarkTargetComponent = NULL;
-                header->nFlags = msg.u.extended_buffer_data.flags;
-                header->nTimeStamp = msg.u.extended_buffer_data.timestamp;
-
-                BufferMeta *buffer_meta =
-                    static_cast<BufferMeta *>(header->pAppPrivate);
-                buffer_meta->CopyToOMX(header);
-
-                NodeMeta *node_meta = static_cast<NodeMeta *>(
-                        msg.u.extended_buffer_data.node);
-
-                LOGV("EmptyThisBuffer buffer=%p", header);
-
-                OMX_ERRORTYPE err =
-                    OMX_EmptyThisBuffer(node_meta->handle(), header);
-                assert(err == OMX_ErrorNone);
-                break;
-            }
-
-            case omx_message::SEND_COMMAND:
-            {
-                NodeMeta *node_meta = static_cast<NodeMeta *>(
-                        msg.u.send_command_data.node);
-
-                OMX_ERRORTYPE err =
-                    OMX_SendCommand(
-                            node_meta->handle(), msg.u.send_command_data.cmd,
-                            msg.u.send_command_data.param, NULL);
-                assert(err == OMX_ErrorNone);
-                break;
-            }
-
-            case omx_message::DISCONNECT:
-            {
-                omx_message msg;
-                msg.type = omx_message::DISCONNECTED;
-                ssize_t n = send(mSock, &msg, sizeof(msg), 0);
-                assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
-                done = true;
-                break;
-            }
-
-            default:
-                LOGE("received unknown omx_message type %d", msg.type);
-                break;
-        }
-    }
-
-    Mutex::Autolock autoLock(mLock);
-    close(mSock);
-    mSock = -1;
-}
-#endif
-
 status_t OMX::list_nodes(List<String8> *list) {
     OMX_MasterInit();  // XXX Put this somewhere else.
 
@@ -362,12 +220,6 @@
         node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
     Mutex::Autolock autoLock(mLock);
 
-#if IOMX_USES_SOCKETS
-    if (mSock < 0) {
-        return UNKNOWN_ERROR;
-    }
-#endif
-
     NodeMeta *meta = static_cast<NodeMeta *>(node);
     OMX_ERRORTYPE err = OMX_SendCommand(meta->handle(), cmd, param, NULL);
 
@@ -510,17 +362,10 @@
     msg.u.event_data.data1 = nData1;
     msg.u.event_data.data2 = nData2;
 
-#if !IOMX_USES_SOCKETS
     sp<IOMXObserver> observer = meta->observer();
     if (observer.get() != NULL) {
         observer->on_message(msg);
     }
-#else
-    assert(mSock >= 0);
-
-    ssize_t n = send(mSock, &msg, sizeof(msg), 0);
-    assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
-#endif
 
     return OMX_ErrorNone;
 }
@@ -534,16 +379,10 @@
     msg.u.buffer_data.node = meta;
     msg.u.buffer_data.buffer = pBuffer;
 
-#if !IOMX_USES_SOCKETS
     sp<IOMXObserver> observer = meta->observer();
     if (observer.get() != NULL) {
         observer->on_message(msg);
     }
-#else
-    assert(mSock >= 0);
-    ssize_t n = send(mSock, &msg, sizeof(msg), 0);
-    assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
-#endif
 
     return OMX_ErrorNone;
 }
@@ -564,22 +403,14 @@
     msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
     msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
 
-#if !IOMX_USES_SOCKETS
     sp<IOMXObserver> observer = meta->observer();
     if (observer.get() != NULL) {
         observer->on_message(msg);
     }
-#else
-    assert(mSock >= 0);
-
-    ssize_t n = send(mSock, &msg, sizeof(msg), 0);
-    assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
-#endif
 
     return OMX_ErrorNone;
 }
 
-#if !IOMX_USES_SOCKETS
 status_t OMX::observe_node(
         node_id node, const sp<IOMXObserver> &observer) {
     NodeMeta *node_meta = static_cast<NodeMeta *>(node);
@@ -623,7 +454,6 @@
         OMX_EmptyThisBuffer(node_meta->handle(), header);
     assert(err == OMX_ErrorNone);
 }
-#endif
 
 ////////////////////////////////////////////////////////////////////////////////
 
diff --git a/media/libstagefright/omx/OMX.h b/media/libstagefright/omx/OMX.h
index 20430bb..8ac311c 100644
--- a/media/libstagefright/omx/OMX.h
+++ b/media/libstagefright/omx/OMX.h
@@ -17,8 +17,6 @@
 #ifndef ANDROID_OMX_H_
 #define ANDROID_OMX_H_
 
-#include <pthread.h>
-
 #include <media/IOMX.h>
 #include <utils/threads.h>
 
@@ -29,11 +27,6 @@
 class OMX : public BnOMX {
 public:
     OMX();
-    virtual ~OMX();
-
-#if IOMX_USES_SOCKETS
-    virtual status_t connect(int *sd);
-#endif
 
     virtual status_t list_nodes(List<String8> *list);
 
@@ -66,7 +59,6 @@
     virtual status_t free_buffer(
             node_id node, OMX_U32 port_index, buffer_id buffer);
 
-#if !IOMX_USES_SOCKETS
     virtual status_t observe_node(
             node_id node, const sp<IOMXObserver> &observer);
 
@@ -77,7 +69,6 @@
             buffer_id buffer,
             OMX_U32 range_offset, OMX_U32 range_length,
             OMX_U32 flags, OMX_TICKS timestamp);
-#endif
 
     virtual sp<IOMXRenderer> createRenderer(
             const sp<ISurface> &surface,
@@ -89,14 +80,6 @@
 private:
     static OMX_CALLBACKTYPE kCallbacks;
 
-#if IOMX_USES_SOCKETS
-    int mSock;
-    pthread_t mThread;
-
-    static void *ThreadWrapper(void *me);
-    void threadEntry();
-#endif
-
     Mutex mLock;
 
     static OMX_ERRORTYPE OnEvent(
diff --git a/opengl/libagl/copybit.cpp b/opengl/libagl/copybit.cpp
index 3c5bcdf3..867459d 100644
--- a/opengl/libagl/copybit.cpp
+++ b/opengl/libagl/copybit.cpp
@@ -75,6 +75,8 @@
 static bool supportedCopybitsFormat(int format) {
     switch (format) {
     case COPYBIT_FORMAT_RGBA_8888:
+    case COPYBIT_FORMAT_RGBX_8888:
+    case COPYBIT_FORMAT_RGB_888:
     case COPYBIT_FORMAT_RGB_565:
     case COPYBIT_FORMAT_BGRA_8888:
     case COPYBIT_FORMAT_RGBA_5551:
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index cf66be3..0762ebf 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -384,6 +384,10 @@
 
 EGLBoolean egl_window_surface_v2_t::connect() 
 {
+    // we're intending to do software rendering
+    native_window_set_usage(nativeWindow, 
+            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+
     // dequeue a buffer
     if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) != NO_ERROR) {
         return setError(EGL_BAD_ALLOC, EGL_FALSE);
diff --git a/opengl/tests/angeles/app-linux.cpp b/opengl/tests/angeles/app-linux.cpp
index 9c71693..06fa0c2 100644
--- a/opengl/tests/angeles/app-linux.cpp
+++ b/opengl/tests/angeles/app-linux.cpp
@@ -133,11 +133,11 @@
      EGLint w, h;
      EGLDisplay dpy;
 
+     EGLNativeWindowType window = android_createDisplaySurface();
+     
      dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
      eglInitialize(dpy, &majorVersion, &minorVersion);
           
-     EGLNativeWindowType window = android_createDisplaySurface();
-     
      status_t err = EGLUtils::selectConfigForNativeWindow(
              dpy, configAttribs, window, &config);
      if (err) {
diff --git a/opengl/tests/copybits/copybits.cpp b/opengl/tests/copybits/copybits.cpp
index f8ca9b2..11dfb6e 100644
--- a/opengl/tests/copybits/copybits.cpp
+++ b/opengl/tests/copybits/copybits.cpp
@@ -23,6 +23,9 @@
 #include <hardware/gralloc.h>
 #include <hardware/hardware.h>
 
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
 #define EGL_EGLEXT_PROTOTYPES
 #define GL_GLEXT_PROTOTYPES
 
@@ -32,8 +35,6 @@
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
-extern "C" EGLNativeWindowType android_createDisplaySurface(void);
-
 using namespace android;
 
 EGLDisplay eglDisplay;
@@ -268,6 +269,8 @@
             EGL_NONE
     };
 
+    EGLNativeWindowType window = android_createDisplaySurface();
+
     printf("init_gl_surface\n");
     if ( (eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY )
     {
@@ -281,14 +284,15 @@
         return 0;
     }
 
-    if ( eglChooseConfig(eglDisplay, attrib, &myConfig, 1, &numConfigs) != EGL_TRUE )
+    if ( EGLUtils::selectConfigForNativeWindow(eglDisplay, attrib, window, &myConfig) != 0)
     {
-        printf("eglChooseConfig failed\n");
+        printf("EGLUtils::selectConfigForNativeWindow failed\n");
         return 0;
     }
+        
 
     if ( (eglSurface = eglCreateWindowSurface(eglDisplay, myConfig,
-            android_createDisplaySurface(), 0)) == EGL_NO_SURFACE )
+            window, 0)) == EGL_NO_SURFACE )
     {
         printf("eglCreateWindowSurface failed\n");
         return 0;
diff --git a/opengl/tests/fillrate/fillrate.cpp b/opengl/tests/fillrate/fillrate.cpp
index 4ffbc8b..911d354 100644
--- a/opengl/tests/fillrate/fillrate.cpp
+++ b/opengl/tests/fillrate/fillrate.cpp
@@ -45,11 +45,11 @@
      EGLint w, h;
      EGLDisplay dpy;
 
+     EGLNativeWindowType window = android_createDisplaySurface();
+     
      dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
      eglInitialize(dpy, &majorVersion, &minorVersion);
           
-     EGLNativeWindowType window = android_createDisplaySurface();
-     
      status_t err = EGLUtils::selectConfigForNativeWindow(
              dpy, configAttribs, window, &config);
      if (err) {
diff --git a/opengl/tests/filter/filter.cpp b/opengl/tests/filter/filter.cpp
index e82b12d..2351909 100644
--- a/opengl/tests/filter/filter.cpp
+++ b/opengl/tests/filter/filter.cpp
@@ -10,6 +10,8 @@
 
 using namespace android;
 
+#define USE_DRAW_TEXTURE 1
+
 int main(int argc, char** argv)
 {
     if (argc!=2 && argc!=3) {
@@ -37,13 +39,17 @@
      
      EGLDisplay dpy;
 
+     EGLNativeWindowType window = 0;
+     if (!usePbuffer) {
+         window = android_createDisplaySurface();
+     }
+     
      dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
      eglInitialize(dpy, &majorVersion, &minorVersion);
      if (!usePbuffer) {
-         EGLNativeWindowType window = android_createDisplaySurface();
-         surface = eglCreateWindowSurface(dpy, config, window, NULL);
          EGLUtils::selectConfigForNativeWindow(
                  dpy, s_configAttribs, window, &config);
+         surface = eglCreateWindowSurface(dpy, config, window, NULL);
      } else {
          printf("using pbuffer\n");
          eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
@@ -59,6 +65,12 @@
      eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
      GLint dim = w<h ? w : h;
 
+     glViewport(0, 0, w, h);
+     glMatrixMode(GL_PROJECTION);
+     glLoadIdentity();
+     glOrthof(0, w, 0, h, 0, 1);
+
+     glClearColor(0,0,0,0);
      glClear(GL_COLOR_BUFFER_BIT);
 
      GLint crop[4] = { 0, 4, 4, -4 };
@@ -124,14 +136,55 @@
          break;
      }
 
-     glDrawTexiOES(0, 0, 0, dim, dim);
+     //glDrawTexiOES(0, 0, 0, dim, dim);
+     
+     const GLfloat vertices[4][2] = {
+             { 0,    0   },
+             { 0,    dim },
+             { dim,  dim },
+             { dim,  0   }
+     };
 
+     const GLfloat texCoords[4][2] = {
+             { 0,  0 },
+             { 0,  1 },
+             { 1,  1 },
+             { 1,  0 }
+     };
+     
      if (!usePbuffer) {
          eglSwapBuffers(dpy, surface);
-     } else {
-         glFinish();
      }
      
+     glMatrixMode(GL_MODELVIEW);
+     glScissor(0,dim,dim,h-dim);
+     glDisable(GL_SCISSOR_TEST);
+     
+     for (int y=0 ; y<dim ; y++) {
+         //glDisable(GL_SCISSOR_TEST);
+         glClear(GL_COLOR_BUFFER_BIT);
+
+         //glEnable(GL_SCISSOR_TEST);
+
+#if USE_DRAW_TEXTURE && GL_OES_draw_texture
+         glDrawTexiOES(0, y, 1, dim, dim);
+#else
+         glLoadIdentity();
+         glTranslatef(0, y, 0);
+         glEnableClientState(GL_VERTEX_ARRAY);
+         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+         glVertexPointer(2, GL_FLOAT, 0, vertices);
+         glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+         glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+#endif
+
+         if (!usePbuffer) {
+             eglSwapBuffers(dpy, surface);
+         } else {
+             glFinish();
+         }
+     }
+
      eglTerminate(dpy);
      return 0;
 }
diff --git a/opengl/tests/finish/finish.cpp b/opengl/tests/finish/finish.cpp
index b5b8142..91f5c45 100644
--- a/opengl/tests/finish/finish.cpp
+++ b/opengl/tests/finish/finish.cpp
@@ -46,11 +46,11 @@
      EGLint w, h;
      EGLDisplay dpy;
 
+     EGLNativeWindowType window = android_createDisplaySurface();
+     
      dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
      eglInitialize(dpy, &majorVersion, &minorVersion);
           
-     EGLNativeWindowType window = android_createDisplaySurface();
-     
      status_t err = EGLUtils::selectConfigForNativeWindow(
              dpy, configAttribs, window, &config);
      if (err) {
diff --git a/opengl/tests/swapinterval/swapinterval.cpp b/opengl/tests/swapinterval/swapinterval.cpp
index cf908a0..df53b62 100644
--- a/opengl/tests/swapinterval/swapinterval.cpp
+++ b/opengl/tests/swapinterval/swapinterval.cpp
@@ -1,21 +1,19 @@
 /*
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
-
-#define LOG_TAG "fillrate"
+ **
+ ** Copyright 2006, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License"); 
+ ** you may not use this file except in compliance with the License. 
+ ** You may obtain a copy of the License at 
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0 
+ **
+ ** Unless required by applicable law or agreed to in writing, software 
+ ** distributed under the License is distributed on an "AS IS" BASIS, 
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ ** See the License for the specific language governing permissions and 
+ ** limitations under the License.
+ */
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -33,72 +31,91 @@
 int main(int argc, char** argv)
 {
     EGLint configAttribs[] = {
-         EGL_DEPTH_SIZE, 0,
-         EGL_NONE
-     };
-     
-     EGLint majorVersion;
-     EGLint minorVersion;
-     EGLContext context;
-     EGLConfig config;
-     EGLSurface surface;
-     EGLint w, h;
-     EGLDisplay dpy;
+            EGL_SURFACE_TYPE,   EGL_WINDOW_BIT,
+            EGL_NONE
+    };
 
-     dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-     eglInitialize(dpy, &majorVersion, &minorVersion);
-          
-     EGLNativeWindowType window = android_createDisplaySurface();
-     
-     status_t err = EGLUtils::selectConfigForNativeWindow(
-             dpy, configAttribs, window, &config);
-     if (err) {
-         fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
-         return 0;
-     }
+    EGLint majorVersion;
+    EGLint minorVersion;
+    EGLContext context;
+    EGLConfig config;
+    EGLint numConfigs=0;
+    EGLSurface surface;
+    EGLint w, h;
+    EGLDisplay dpy;
 
-     surface = eglCreateWindowSurface(dpy, config, window, NULL);
-     context = eglCreateContext(dpy, config, NULL, NULL);
-     eglMakeCurrent(dpy, surface, surface, context);   
-     eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
-     eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
-     
-     printf("w=%d, h=%d\n", w, h);
-     
-     glDisable(GL_DITHER);
-     glEnable(GL_BLEND);
+    
+    EGLNativeWindowType window = android_createDisplaySurface();
 
-     glViewport(0, 0, w, h);
-     glOrthof(0, w, 0, h, 0, 1);
+    dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    eglInitialize(dpy, 0 ,0) ;//&majorVersion, &minorVersion);
+    eglGetConfigs(dpy, NULL, 0, &numConfigs);
+    printf("# configs = %d\n", numConfigs);
 
-     eglSwapInterval(dpy, 1);
+    status_t err = EGLUtils::selectConfigForNativeWindow(
+            dpy, configAttribs, window, &config);
+    if (err) {
+        fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+        return 0;
+    }
 
-     glClearColor(1,0,0,0);
-     glClear(GL_COLOR_BUFFER_BIT);
-     eglSwapBuffers(dpy, surface);
+    EGLint r,g,b,a;
+    eglGetConfigAttrib(dpy, config, EGL_RED_SIZE,   &r);
+    eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g);
+    eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE,  &b);
+    eglGetConfigAttrib(dpy, config, EGL_ALPHA_SIZE, &a);
+
+    surface = eglCreateWindowSurface(dpy, config, window, NULL);
+    if (surface == EGL_NO_SURFACE) {
+        EGLint err = eglGetError();
+        fprintf(stderr, "%s, config=%p, format = %d-%d-%d-%d\n",
+                EGLUtils::strerror(err), config, r,g,b,a);
+        return 0;
+    } else {
+        printf("config=%p, format = %d-%d-%d-%d\n", config, r,g,b,a);
+    }
+
+    context = eglCreateContext(dpy, config, NULL, NULL);
+    eglMakeCurrent(dpy, surface, surface, context);   
+    eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+    eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+
+    printf("w=%d, h=%d\n", w, h);
+
+    glDisable(GL_DITHER);
+    glEnable(GL_BLEND);
+
+    glViewport(0, 0, w, h);
+    glOrthof(0, w, 0, h, 0, 1);
+
+    eglSwapInterval(dpy, 1);
+
+    glClearColor(1,0,0,0);
+    glClear(GL_COLOR_BUFFER_BIT);
+    eglSwapBuffers(dpy, surface);
 
 
-     int time = 10;
-     printf("screen should flash red/green quickly for %d s...\n", time);
-     
-     int c = 0;
-     nsecs_t start = systemTime();
-     nsecs_t t;
-     do {
-         glClearColor(1,0,0,0);
-         glClear(GL_COLOR_BUFFER_BIT);
-         eglSwapBuffers(dpy, surface);
-         glClearColor(0,1,0,0);
-         glClear(GL_COLOR_BUFFER_BIT);
-         eglSwapBuffers(dpy, surface);
-         t = systemTime() - start;
-         c += 2;
-     } while (int(ns2s(t))<=time);
-     
-     double p =  (double(t) / c) / 1000000000.0;
-     printf("refresh-rate is %f fps (%f ms)\n", 1.0f/p, p*1000.0);
-       
-     eglTerminate(dpy);
-     
-     return 0;
+    int time = 10;
+    printf("screen should flash red/green quickly for %d s...\n", time);
+
+    int c = 0;
+    nsecs_t start = systemTime();
+    nsecs_t t;
+    do {
+        glClearColor(1,0,0,0);
+        glClear(GL_COLOR_BUFFER_BIT);
+        eglSwapBuffers(dpy, surface);
+        glClearColor(0,1,0,0);
+        glClear(GL_COLOR_BUFFER_BIT);
+        eglSwapBuffers(dpy, surface);
+        t = systemTime() - start;
+        c += 2;
+    } while (int(ns2s(t))<=time);
+
+    double p =  (double(t) / c) / 1000000000.0;
+    printf("refresh-rate is %f fps (%f ms)\n", 1.0f/p, p*1000.0);
+
+    eglTerminate(dpy);
+
+    return 0;
 }
diff --git a/opengl/tests/textures/textures.cpp b/opengl/tests/textures/textures.cpp
index ee92e79..cbe8ffd 100644
--- a/opengl/tests/textures/textures.cpp
+++ b/opengl/tests/textures/textures.cpp
@@ -42,11 +42,11 @@
      EGLint w, h;
      EGLDisplay dpy;
 
+     EGLNativeWindowType window = android_createDisplaySurface();
+     
      dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
      eglInitialize(dpy, &majorVersion, &minorVersion);
           
-     EGLNativeWindowType window = android_createDisplaySurface();
-     
      status_t err = EGLUtils::selectConfigForNativeWindow(
              dpy, configAttribs, window, &config);
      if (err) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index e53171f..a5bd254 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -83,6 +83,11 @@
     };
 
     private static final String FILE_WIFI_SUPPLICANT = "/data/misc/wifi/wpa_supplicant.conf";
+
+    // the key to store the WIFI data under, should be sorted as last, so restore happens last.
+    // use very late unicode character to quasi-guarantee last sort position.
+    private static final String KEY_WIFI_SUPPLICANT = "\uffeeWIFI";
+
     private static final String FILE_BT_ROOT = "/data/misc/hcid/";
 
     private SettingsHelper mSettingsHelper;
@@ -113,7 +118,7 @@
         stateChecksums[STATE_LOCALE] =
                 writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
         stateChecksums[STATE_WIFI] =
-                writeIfChanged(stateChecksums[STATE_WIFI], FILE_WIFI_SUPPLICANT, wifiData, data);
+                writeIfChanged(stateChecksums[STATE_WIFI], KEY_WIFI_SUPPLICANT, wifiData, data);
 
         writeNewChecksums(stateChecksums, newState);
     }
@@ -133,7 +138,7 @@
                 mSettingsHelper.applyAudioSettings();
             } else if (KEY_SECURE.equals(key)) {
                 restoreSettings(data, Settings.Secure.CONTENT_URI);
-            } else if (FILE_WIFI_SUPPLICANT.equals(key)) {
+            } else if (KEY_WIFI_SUPPLICANT.equals(key)) {
                 int retainedWifiState = enableWifi(false);
                 restoreFile(FILE_WIFI_SUPPLICANT, data);
                 FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnService.java b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
index f410c7b..e3ac996 100644
--- a/packages/VpnServices/src/com/android/server/vpn/VpnService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
@@ -133,11 +133,7 @@
 
         if (VpnState.CONNECTED.equals(mState)) {
             Log.i("VpnService", "     recovered: " + mProfile.getName());
-            new Thread(new Runnable() {
-                public void run() {
-                    enterConnectivityLoop();
-                }
-            }).start();
+            startConnectivityMonitor();
         }
     }
 
@@ -213,16 +209,18 @@
                     SystemProperties.get(VPN_STATUS))) {
                 onConnected();
                 return;
-            } else if (mDaemonHelper.anySocketError()) {
-                return;
+            } else {
+                int err = mDaemonHelper.getSocketError();
+                if (err != 0) {
+                    onError(err);
+                    return;
+                }
             }
             sleep(500); // 0.5 second
         }
 
-        synchronized (VpnService.this) {
-            if (mState == VpnState.CONNECTING) {
-                onError(new IOException("Connecting timed out"));
-            }
+        if (mState == VpnState.CONNECTING) {
+            onError(new IOException("Connecting timed out"));
         }
     }
 
@@ -235,13 +233,15 @@
 
         mStartTime = System.currentTimeMillis();
 
-        // set DNS after saving the states in case the process gets killed
-        // before states are saved
+        // Correct order to make sure VpnService doesn't break when killed:
+        // (1) set state to CONNECTED
+        // (2) save states
+        // (3) set DNS
+        setState(VpnState.CONNECTED);
         saveSelf();
         setVpnDns();
-        setState(VpnState.CONNECTED);
 
-        enterConnectivityLoop();
+        startConnectivityMonitor();
     }
 
     private void saveSelf() throws IOException {
@@ -340,23 +340,28 @@
         }
     }
 
-    private void enterConnectivityLoop() {
-        Log.i(TAG, "VPN connectivity monitor running");
-        try {
-            for (;;) {
-                synchronized (VpnService.this) {
-                    if (mState != VpnState.CONNECTED || !checkConnectivity()) {
-                        break;
+    private void startConnectivityMonitor() {
+        new Thread(new Runnable() {
+            public void run() {
+                Log.i(TAG, "VPN connectivity monitor running");
+                try {
+                    for (;;) {
+                        synchronized (VpnService.this) {
+                            if ((mState != VpnState.CONNECTED)
+                                || !checkConnectivity()) {
+                                break;
+                            }
+                            mNotification.update();
+                            checkDns();
+                            VpnService.this.wait(1000); // 1 second
+                        }
                     }
-                    mNotification.update();
-                    checkDns();
-                    VpnService.this.wait(1000); // 1 second
+                } catch (InterruptedException e) {
+                    onError(e);
                 }
+                Log.i(TAG, "VPN connectivity monitor stopped");
             }
-        } catch (InterruptedException e) {
-            onError(e);
-        }
-        Log.i(TAG, "VPN connectivity monitor stopped");
+        }).start();
     }
 
     private void saveLocalIpAndInterface(String serverIp) throws IOException {
@@ -432,11 +437,7 @@
         }
 
         synchronized void stopAll() {
-            if (mDaemonList.isEmpty()) {
-                onFinalCleanUp();
-            } else {
-                for (DaemonProxy s : mDaemonList) s.stop();
-            }
+            for (DaemonProxy s : mDaemonList) s.stop();
         }
 
         synchronized void closeSockets() {
@@ -461,30 +462,26 @@
             }
         }
 
-        synchronized boolean anySocketError() {
+        synchronized int getSocketError() {
             for (DaemonProxy s : mDaemonList) {
                 switch (getResultFromSocket(s)) {
                     case 0:
                         continue;
 
                     case AUTH_ERROR_CODE:
-                        onError(VpnManager.VPN_ERROR_AUTH);
-                        return true;
+                        return VpnManager.VPN_ERROR_AUTH;
 
                     case CHALLENGE_ERROR_CODE:
-                        onError(VpnManager.VPN_ERROR_CHALLENGE);
-                        return true;
+                        return VpnManager.VPN_ERROR_CHALLENGE;
 
                     case REMOTE_HUNG_UP_ERROR_CODE:
-                        onError(VpnManager.VPN_ERROR_REMOTE_HUNG_UP);
-                        return true;
+                        return VpnManager.VPN_ERROR_REMOTE_HUNG_UP;
 
                     default:
-                        onError(VpnManager.VPN_ERROR_CONNECTION_FAILED);
-                        return true;
+                        return VpnManager.VPN_ERROR_CONNECTION_FAILED;
                 }
             }
-            return false;
+            return 0;
         }
     }
 
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index ed16a37..36dca7d 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -792,11 +792,15 @@
 
         synchronized(mClearDataLock) {
             mClearingData = true;
+            /* This is causing some critical processes to be killed during setup.
+               Temporarily revert this change until we find a better solution.
             try {
                 mActivityManager.clearApplicationUserData(packageName, observer);
             } catch (RemoteException e) {
                 // can't happen because the activity manager is in this process
             }
+            */
+            mPackageManager.clearApplicationUserData(packageName, observer);
 
             // only wait 10 seconds for the clear data to happen
             long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
@@ -1079,7 +1083,7 @@
         public void run() {
             long startRealtime = SystemClock.elapsedRealtime();
             if (DEBUG) Log.v(TAG, "Beginning restore process mTransport=" + mTransport
-                    + " mObserver=" + mObserver + " mToken=" + mToken);
+                    + " mObserver=" + mObserver + " mToken=" + Long.toHexString(mToken));
             /**
              * Restore sequence:
              *
@@ -1702,7 +1706,8 @@
             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                     "performRestore");
 
-            if (DEBUG) Log.d(TAG, "performRestore token=" + token + " observer=" + observer);
+            if (DEBUG) Log.d(TAG, "performRestore token=" + Long.toHexString(token)
+                    + " observer=" + observer);
 
             if (mRestoreTransport == null || mRestoreSets == null) {
                 Log.e(TAG, "Ignoring performRestore() with no restore set");
@@ -1720,6 +1725,8 @@
                     return 0;
                 }
             }
+
+            Log.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
             return -1;
         }
 
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index c5fd985..06565c7 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -22,19 +22,30 @@
 import android.app.IWallpaperManager;
 import android.app.IWallpaperManagerCallback;
 import android.backup.BackupManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.os.Binder;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.FileObserver;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteCallbackList;
-import android.util.Config;
+import android.os.ServiceManager;
+import android.service.wallpaper.IWallpaperConnection;
+import android.service.wallpaper.IWallpaperEngine;
+import android.service.wallpaper.IWallpaperService;
+import android.service.wallpaper.WallpaperService;
 import android.util.Log;
 import android.util.Xml;
+import android.view.IWindowManager;
+import android.view.WindowManager;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -42,6 +53,7 @@
 import java.io.FileNotFoundException;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.util.List;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -50,9 +62,10 @@
 import com.android.internal.util.FastXmlSerializer;
 
 class WallpaperManagerService extends IWallpaperManager.Stub {
-    private static final String TAG = "WallpaperService";
+    static final String TAG = "WallpaperService";
+    static final boolean DEBUG = true;
 
-    private Object mLock = new Object();
+    Object mLock = new Object();
 
     private static final File WALLPAPER_DIR = new File(
             "/data/data/com.android.settings/files");
@@ -94,15 +107,60 @@
                 }
             };
     
-    private final Context mContext;
+    final Context mContext;
+    final IWindowManager mIWindowManager;
 
-    private int mWidth = -1;
-    private int mHeight = -1;
-    private String mName = "";
+    int mWidth = -1;
+    int mHeight = -1;
+    String mName = "";
+    ComponentName mWallpaperComponent;
+    WallpaperConnection mWallpaperConnection;
+    
+    class WallpaperConnection extends IWallpaperConnection.Stub
+            implements ServiceConnection {
+        final Binder mToken = new Binder();
+        IWallpaperService mService;
+        IWallpaperEngine mEngine;
 
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            synchronized (mLock) {
+                if (mWallpaperConnection == this) {
+                    mService = IWallpaperService.Stub.asInterface(service);
+                    attachServiceLocked(this);
+                }
+            }
+        }
+
+        public void onServiceDisconnected(ComponentName name) {
+            synchronized (mLock) {
+                mService = null;
+                mEngine = null;
+            }
+        }
+        
+        public void attachEngine(IWallpaperEngine engine) {
+            mEngine = engine;
+        }
+        
+        public ParcelFileDescriptor setWallpaper(String name) {
+            synchronized (mLock) {
+                if (mWallpaperConnection == this) {
+                    ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name);
+                    if (pfd != null) {
+                        saveSettingsLocked();
+                    }
+                    return pfd;
+                }
+                return null;
+            }
+        }
+    }
+    
     public WallpaperManagerService(Context context) {
-        if (Config.LOGD) Log.d(TAG, "WallpaperService startup");
+        if (DEBUG) Log.d(TAG, "WallpaperService startup");
         mContext = context;
+        mIWindowManager = IWindowManager.Stub.asInterface(
+                ServiceManager.getService(Context.WINDOW_SERVICE));
         WALLPAPER_DIR.mkdirs();
         loadSettingsLocked();
         mWallpaperObserver.startWatching();
@@ -162,7 +220,7 @@
                 return ParcelFileDescriptor.open(f, MODE_READ_ONLY);
             } catch (FileNotFoundException e) {
                 /* Shouldn't happen as we check to see if the file exists */
-                if (Config.LOGD) Log.d(TAG, "Error getting wallpaper", e);
+                Log.w(TAG, "Error getting wallpaper", e);
             }
             return null;
         }
@@ -171,20 +229,108 @@
     public ParcelFileDescriptor setWallpaper(String name) {
         checkPermission(android.Manifest.permission.SET_WALLPAPER);
         synchronized (mLock) {
-            if (name == null) name = "";
-            mName = name;
-            saveSettingsLocked();
-            try {
-                ParcelFileDescriptor fd = ParcelFileDescriptor.open(WALLPAPER_FILE,
-                        MODE_CREATE|MODE_READ_WRITE);
-                return fd;
-            } catch (FileNotFoundException e) {
-                if (Config.LOGD) Log.d(TAG, "Error setting wallpaper", e);
+            ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name);
+            if (pfd != null) {
+                clearWallpaperComponentLocked();
+                saveSettingsLocked();
             }
-            return null;
+            return pfd;
         }
     }
 
+    ParcelFileDescriptor updateWallpaperBitmapLocked(String name) {
+        if (name == null) name = "";
+        try {
+            ParcelFileDescriptor fd = ParcelFileDescriptor.open(WALLPAPER_FILE,
+                    MODE_CREATE|MODE_READ_WRITE);
+            mName = name;
+            return fd;
+        } catch (FileNotFoundException e) {
+            Log.w(TAG, "Error setting wallpaper", e);
+        }
+        return null;
+    }
+
+    public void setWallpaperComponent(ComponentName name) {
+        checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
+        synchronized (mLock) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                ServiceInfo si = mContext.getPackageManager().getServiceInfo(name,
+                        PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS);
+                if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) {
+                    throw new SecurityException("Selected service does not require "
+                            + android.Manifest.permission.BIND_WALLPAPER
+                            + ": " + name);
+                }
+                
+                // Make sure the selected service is actually a wallpaper service.
+                Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
+                List<ResolveInfo> ris = mContext.getPackageManager()
+                        .queryIntentServices(intent, 0);
+                for (int i=0; i<ris.size(); i++) {
+                    ServiceInfo rsi = ris.get(i).serviceInfo;
+                    if (rsi.name.equals(si.name) &&
+                            rsi.packageName.equals(si.packageName)) {
+                        ris = null;
+                        break;
+                    }
+                }
+                if (ris != null) {
+                    throw new SecurityException("Selected service is not a wallpaper: "
+                            + name);
+                }
+                
+                // Bind the service!
+                WallpaperConnection newConn = new WallpaperConnection();
+                intent.setComponent(name);
+                if (!mContext.bindService(intent, newConn,
+                        Context.BIND_AUTO_CREATE)) {
+                    throw new IllegalArgumentException("Unable to bind service: "
+                            + name);
+                }
+                
+                clearWallpaperComponentLocked();
+                mWallpaperComponent = null;
+                mWallpaperConnection = newConn;
+                try {
+                    if (DEBUG) Log.v(TAG, "Adding window token: " + newConn.mToken);
+                    mIWindowManager.addWindowToken(newConn.mToken,
+                            WindowManager.LayoutParams.TYPE_WALLPAPER);
+                } catch (RemoteException e) {
+                }
+                
+            } catch (PackageManager.NameNotFoundException e) {
+                throw new IllegalArgumentException("Unknown component " + name);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+    
+    void clearWallpaperComponentLocked() {
+        mWallpaperComponent = null;
+        if (mWallpaperConnection != null) {
+            if (mWallpaperConnection.mEngine != null) {
+                try {
+                    mWallpaperConnection.mEngine.destroy();
+                } catch (RemoteException e) {
+                }
+            }
+            mContext.unbindService(mWallpaperConnection);
+            mWallpaperConnection = null;
+        }
+    }
+    
+    void attachServiceLocked(WallpaperConnection conn) {
+        try {
+            conn.mService.attach(conn, conn.mToken, mWidth, mHeight);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed attaching wallpaper; clearing", e);
+            clearWallpaperComponentLocked();
+        }
+    }
+    
     private void notifyCallbacksLocked() {
         final int n = mCallbacks.beginBroadcast();
         for (int i = 0; i < n; i++) {
@@ -226,6 +372,10 @@
             out.attribute(null, "width", Integer.toString(mWidth));
             out.attribute(null, "height", Integer.toString(mHeight));
             out.attribute(null, "name", mName);
+            if (mWallpaperComponent != null) {
+                out.attribute(null, "component",
+                        mWallpaperComponent.flattenToShortString());
+            }
             out.endTag(null, "wp");
 
             out.endDocument();
@@ -254,7 +404,6 @@
             parser.setInput(stream, null);
 
             int type;
-            int providerIndex = 0;
             do {
                 type = parser.next();
                 if (type == XmlPullParser.START_TAG) {
@@ -263,6 +412,10 @@
                         mWidth = Integer.parseInt(parser.getAttributeValue(null, "width"));
                         mHeight = Integer.parseInt(parser.getAttributeValue(null, "height"));
                         mName = parser.getAttributeValue(null, "name");
+                        String comp = parser.getAttributeValue(null, "component");
+                        mWallpaperComponent = comp != null
+                                ? ComponentName.unflattenFromString(comp)
+                                : null;
                     }
                 }
             } while (type != XmlPullParser.END_DOCUMENT);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index ceb9c41..641f251 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -31,6 +31,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_GPU;
@@ -40,6 +41,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.policy.PolicyManager;
@@ -399,6 +401,13 @@
     WindowState mInputMethodWindow = null;
     final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<WindowState>();
 
+    final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>();
+    
+    // If non-null, this is the currently visible window that is associated
+    // with the wallpaper.
+    WindowState mWallpaperTarget = null;
+    int mWallpaperAnimLayerAdjustment;
+    
     AppWindowToken mFocusedApp = null;
 
     PowerManagerService mPowerManager;
@@ -1167,6 +1176,178 @@
         moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
     }
 
+    boolean adjustWallpaperWindowsLocked() {
+        boolean changed = false;
+        
+        // First find top-most window that has asked to be on top of the
+        // wallpaper; all wallpapers go behind it.
+        final ArrayList localmWindows = mWindows;
+        int N = localmWindows.size();
+        WindowState w = null;
+        int i = N;
+        boolean visible = false;
+        while (i > 0) {
+            i--;
+            w = (WindowState)localmWindows.get(i);
+            if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 && w.isReadyForDisplay()) {
+                visible = true;
+                break;
+            }
+        }
+
+        if (!visible) w = null;
+        mWallpaperTarget = w;
+        
+        if (visible) {
+            mWallpaperAnimLayerAdjustment = w.mAppToken != null
+                    ? w.mAppToken.animLayerAdjustment : 0;
+            
+            // Now w is the window we are supposed to be behind...  but we
+            // need to be sure to also be behind any of its attached windows,
+            // AND any starting window associated with it.
+            while (i > 0) {
+                WindowState wb = (WindowState)localmWindows.get(i-1);
+                if (wb.mAttachedWindow != w &&
+                        (wb.mAttrs.type != TYPE_APPLICATION_STARTING ||
+                                wb.mToken != w.mToken)) {
+                    // This window is not related to the previous one in any
+                    // interesting way, so stop here.
+                    break;
+                }
+                w = wb;
+                i--;
+            }
+        }
+        
+        // Okay i is the position immediately above the wallpaper.  Look at
+        // what is below it for later.
+        w = i > 0 ? (WindowState)localmWindows.get(i-1) : null;
+        
+        final int dw = mDisplay.getWidth();
+        final int dh = mDisplay.getHeight();
+        
+        // Start stepping backwards from here, ensuring that our wallpaper windows
+        // are correctly placed.
+        int curTokenIndex = mWallpaperTokens.size();
+        while (curTokenIndex > 0) {
+            curTokenIndex--;
+            WindowToken token = mWallpaperTokens.get(curTokenIndex);
+            int curWallpaperIndex = token.windows.size();
+            while (curWallpaperIndex > 0) {
+                curWallpaperIndex--;
+                WindowState wallpaper = token.windows.get(curWallpaperIndex);
+                
+                // First, make sure the client has the current visibility
+                // state.
+                if (wallpaper.mWallpaperVisible != visible) {
+                    wallpaper.mWallpaperVisible = visible;
+                    try {
+                        if (DEBUG_VISIBILITY) Log.v(TAG,
+                                "Setting visibility of wallpaper " + wallpaper
+                                + ": " + visible);
+                        wallpaper.mClient.dispatchAppVisibility(visible);
+                    } catch (RemoteException e) {
+                    }
+                }
+                
+                if (visible) {
+                    updateWallpaperOffsetLocked(mWallpaperTarget, wallpaper, dw, dh);                        
+                }
+                
+                wallpaper.mAnimLayer = wallpaper.mLayer + mWallpaperAnimLayerAdjustment;
+                if (DEBUG_LAYERS) Log.v(TAG, "Wallpaper win " + wallpaper
+                        + " anim layer: " + wallpaper.mAnimLayer);
+                
+                // First, if this window is at the current index, then all
+                // is well.
+                if (wallpaper == w) {
+                    i--;
+                    w = i > 0 ? (WindowState)localmWindows.get(i-1) : null;
+                    continue;
+                }
+                
+                // The window didn't match...  the current wallpaper window,
+                // wherever it is, is in the wrong place, so make sure it is
+                // not in the list.
+                int oldIndex = localmWindows.indexOf(wallpaper);
+                if (oldIndex >= 0) {
+                    localmWindows.remove(oldIndex);
+                    if (oldIndex < i) {
+                        i--;
+                    }
+                }
+                
+                // Now stick it in.
+                localmWindows.add(i, wallpaper);
+                changed = true;
+            }
+        }
+        
+        return changed;
+    }
+
+    void setWallpaperAnimLayerAdjustmentLocked(int adj) {
+        if (DEBUG_LAYERS) Log.v(TAG, "Setting wallpaper layer adj to " + adj);
+        mWallpaperAnimLayerAdjustment = adj;
+        int curTokenIndex = mWallpaperTokens.size();
+        while (curTokenIndex > 0) {
+            curTokenIndex--;
+            WindowToken token = mWallpaperTokens.get(curTokenIndex);
+            int curWallpaperIndex = token.windows.size();
+            while (curWallpaperIndex > 0) {
+                curWallpaperIndex--;
+                WindowState wallpaper = token.windows.get(curWallpaperIndex);
+                wallpaper.mAnimLayer = wallpaper.mLayer + adj;
+                if (DEBUG_LAYERS) Log.v(TAG, "Wallpaper win " + wallpaper
+                        + " anim layer: " + wallpaper.mAnimLayer);
+            }
+        }
+    }
+
+    boolean updateWallpaperOffsetLocked(WindowState target,
+            WindowState wallpaperWin, int dw, int dh) {
+        int availw = wallpaperWin.mFrame.right-wallpaperWin.mFrame.left-dw;
+        int offset = availw > 0 ? -(int)(availw*target.mWallpaperX+.5f) : 0;
+        boolean changed = wallpaperWin.mXOffset != offset;
+        if (changed) {
+            wallpaperWin.mXOffset = offset;
+        }
+        int availh = wallpaperWin.mFrame.bottom-wallpaperWin.mFrame.top-dh;
+        offset = availh > 0 ? -(int)(availh*target.mWallpaperY+.5f) : 0;
+        if (wallpaperWin.mYOffset != offset) {
+            changed = true;
+            wallpaperWin.mYOffset = offset;
+        }
+        return changed;
+    }
+    
+    boolean updateWallpaperOffsetLocked() {
+        final int dw = mDisplay.getWidth();
+        final int dh = mDisplay.getHeight();
+        
+        boolean changed = false;
+        
+        WindowState target = mWallpaperTarget;
+        if (target != null) {
+            int curTokenIndex = mWallpaperTokens.size();
+            while (curTokenIndex > 0) {
+                curTokenIndex--;
+                WindowToken token = mWallpaperTokens.get(curTokenIndex);
+                int curWallpaperIndex = token.windows.size();
+                while (curWallpaperIndex > 0) {
+                    curWallpaperIndex--;
+                    WindowState wallpaper = token.windows.get(curWallpaperIndex);
+                    if (updateWallpaperOffsetLocked(target, wallpaper, dw, dh)) {
+                        wallpaper.computeShownFrameLocked();
+                        changed = true;
+                    }
+                }
+            }
+        }
+        
+        return changed;
+    }
+    
     public int addWindow(Session session, IWindow client,
             WindowManager.LayoutParams attrs, int viewVisibility,
             Rect outContentInsets) {
@@ -1224,6 +1405,11 @@
                           + attrs.token + ".  Aborting.");
                     return WindowManagerImpl.ADD_BAD_APP_TOKEN;
                 }
+                if (attrs.type == TYPE_WALLPAPER) {
+                    Log.w(TAG, "Attempted to add wallpaper window with unknown token "
+                          + attrs.token + ".  Aborting.");
+                    return WindowManagerImpl.ADD_BAD_APP_TOKEN;
+                }
                 token = new WindowToken(attrs.token, -1, false);
                 addToken = true;
             } else if (attrs.type >= FIRST_APPLICATION_WINDOW
@@ -1250,6 +1436,12 @@
                             + attrs.token + ".  Aborting.");
                       return WindowManagerImpl.ADD_BAD_APP_TOKEN;
                 }
+            } else if (attrs.type == TYPE_WALLPAPER) {
+                if (token.windowType != TYPE_WALLPAPER) {
+                    Log.w(TAG, "Attempted to add wallpaper window with bad token "
+                            + attrs.token + ".  Aborting.");
+                      return WindowManagerImpl.ADD_BAD_APP_TOKEN;
+                }
             }
 
             win = new WindowState(session, client, token,
@@ -1300,6 +1492,10 @@
                 imMayMove = false;
             } else {
                 addWindowToListInOrderLocked(win, true);
+                if (attrs.type == TYPE_WALLPAPER ||
+                        (attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
+                    adjustWallpaperWindowsLocked();
+                }
             }
 
             win.mEnterAnimationPending = true;
@@ -1461,6 +1657,11 @@
             mInputMethodDialogs.remove(win);
         }
 
+        if (win.mAttrs.type == TYPE_WALLPAPER ||
+                (win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
+            adjustWallpaperWindowsLocked();
+        }
+        
         final WindowToken token = win.mToken;
         final AppWindowToken atoken = win.mAppToken;
         token.windows.remove(win);
@@ -1560,6 +1761,19 @@
         }
     }
 
+    public void setWindowWallpaperPositionLocked(WindowState window, float x, float y) {
+        if (window.mWallpaperX != x || window.mWallpaperY != y)  {
+            window.mWallpaperX = x;
+            window.mWallpaperY = y;
+            
+            if (mWallpaperTarget == window) {
+                if (updateWallpaperOffsetLocked()) {
+                    performLayoutAndPlaceSurfacesLocked();
+                }
+            }
+        }
+    }
+    
     public int relayoutWindow(Session session, IWindow client,
             WindowManager.LayoutParams attrs, int requestedWidth,
             int requestedHeight, int viewVisibility, boolean insetsPending,
@@ -1618,6 +1832,9 @@
                     || ((flagChanges&WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0)
                     || (!win.mRelayoutCalled);
 
+            boolean wallpaperMayMove = win.mViewVisibility != viewVisibility
+                    && (win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
+            
             win.mRelayoutCalled = true;
             final int oldVisibility = win.mViewVisibility;
             win.mViewVisibility = viewVisibility;
@@ -1715,6 +1932,11 @@
                     assignLayers = true;
                 }
             }
+            if (wallpaperMayMove) {
+                if (adjustWallpaperWindowsLocked()) {
+                    assignLayers = true;
+                }
+            }
 
             mLayoutNeeded = true;
             win.mGivenInsetsPending = insetsPending;
@@ -1758,6 +1980,9 @@
         synchronized(mWindowMap) {
             WindowState win = windowForClientLocked(session, client);
             if (win != null && win.finishDrawingLocked()) {
+                if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
+                    adjustWallpaperWindowsLocked();
+                }
                 mLayoutNeeded = true;
                 performLayoutAndPlaceSurfacesLocked();
             }
@@ -2010,6 +2235,9 @@
             wtoken = new WindowToken(token, type, true);
             mTokenMap.put(token, wtoken);
             mTokenList.add(wtoken);
+            if (type == TYPE_WALLPAPER) {
+                mWallpaperTokens.add(wtoken);
+            }
         }
     }
 
@@ -2055,6 +2283,8 @@
 
                     if (delayed) {
                         mExitingTokens.add(wtoken);
+                    } else if (wtoken.windowType == TYPE_WALLPAPER) {
+                        mWallpaperTokens.remove(wtoken);
                     }
                 }
 
@@ -5644,6 +5874,18 @@
             }
         }
 
+        public void setWallpaperPosition(IBinder window, float x, float y) {
+            synchronized(mWindowMap) {
+                long ident = Binder.clearCallingIdentity();
+                try {
+                    setWindowWallpaperPositionLocked(windowForClientLocked(this, window),
+                            x, y);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            }
+        }
+        
         void windowAddedLocked() {
             if (mSurfaceSession == null) {
                 if (localLOGV) Log.v(
@@ -5719,6 +5961,8 @@
         final int mSubLayer;
         final boolean mLayoutAttached;
         final boolean mIsImWindow;
+        final boolean mIsWallpaper;
+        final boolean mIsFloatingLayer;
         int mViewVisibility;
         boolean mPolicyVisibility = true;
         boolean mPolicyVisibilityAfterAnim = true;
@@ -5726,12 +5970,13 @@
         Surface mSurface;
         boolean mAttachedHidden;    // is our parent window hidden?
         boolean mLastHidden;        // was this window last hidden?
+        boolean mWallpaperVisible;  // for wallpaper, what was last vis report?
         int mRequestedWidth;
         int mRequestedHeight;
         int mLastRequestedWidth;
         int mLastRequestedHeight;
-        int mReqXPos;
-        int mReqYPos;
+        int mXOffset;
+        int mYOffset;
         int mLayer;
         int mAnimLayer;
         int mLastLayer;
@@ -5816,6 +6061,9 @@
         boolean mHasLocalTransformation;
         final Transformation mTransformation = new Transformation();
 
+        float mWallpaperX = 0;
+        float mWallpaperY = 0;
+        
         // This is set after IWindowSession.relayout() has been called at
         // least once for the window.  It allows us to detect the situation
         // where we don't yet have a surface, but should have one soon, so
@@ -5876,6 +6124,8 @@
                 mAttachedWindow = null;
                 mLayoutAttached = false;
                 mIsImWindow = false;
+                mIsWallpaper = false;
+                mIsFloatingLayer = false;
                 mBaseLayer = 0;
                 mSubLayer = 0;
                 return;
@@ -5896,6 +6146,8 @@
                         WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
                 mIsImWindow = attachedWindow.mAttrs.type == TYPE_INPUT_METHOD
                         || attachedWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
+                mIsWallpaper = attachedWindow.mAttrs.type == TYPE_WALLPAPER;
+                mIsFloatingLayer = mIsImWindow || mIsWallpaper;
             } else {
                 // The multiplier here is to reserve space for multiple
                 // windows in the same type layer.
@@ -5907,6 +6159,8 @@
                 mLayoutAttached = false;
                 mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
                         || mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
+                mIsWallpaper = mAttrs.type == TYPE_WALLPAPER;
+                mIsFloatingLayer = mIsImWindow || mIsWallpaper;
             }
 
             WindowState appWin = this;
@@ -5929,8 +6183,8 @@
             mRequestedHeight = 0;
             mLastRequestedWidth = 0;
             mLastRequestedHeight = 0;
-            mReqXPos = 0;
-            mReqYPos = 0;
+            mXOffset = 0;
+            mYOffset = 0;
             mLayer = 0;
             mAnimLayer = 0;
             mLastLayer = 0;
@@ -6396,6 +6650,8 @@
             mAnimLayer = mLayer;
             if (mIsImWindow) {
                 mAnimLayer += mInputMethodAnimLayerAdjustment;
+            } else if (mIsWallpaper) {
+                mAnimLayer += mWallpaperAnimLayerAdjustment;
             }
             if (DEBUG_LAYERS) Log.v(TAG, "Stepping win " + this
                     + " anim layer: " + mAnimLayer);
@@ -6482,6 +6738,19 @@
             Transformation appTransformation =
                     (mAppToken != null && mAppToken.hasTransformation)
                     ? mAppToken.transformation : null;
+            
+            // Wallpapers are animated based on the "real" window they
+            // are currently targeting.
+            if (mAttrs.type == TYPE_WALLPAPER && mWallpaperTarget != null) {
+                if (mWallpaperTarget.mHasLocalTransformation) {
+                    attachedTransformation = mWallpaperTarget.mTransformation;
+                }
+                if (mWallpaperTarget.mAppToken != null &&
+                        mWallpaperTarget.mAppToken.hasTransformation) {
+                    appTransformation = mWallpaperTarget.mAppToken.transformation;
+                }
+            }
+            
             if (selfTransformation || attachedTransformation != null
                     || appTransformation != null) {
                 // cache often used attributes locally
@@ -6512,8 +6781,8 @@
                 mDtDx = tmpFloats[Matrix.MSKEW_X];
                 mDsDy = tmpFloats[Matrix.MSKEW_Y];
                 mDtDy = tmpFloats[Matrix.MSCALE_Y];
-                int x = (int)tmpFloats[Matrix.MTRANS_X];
-                int y = (int)tmpFloats[Matrix.MTRANS_Y];
+                int x = (int)tmpFloats[Matrix.MTRANS_X] + mXOffset;
+                int y = (int)tmpFloats[Matrix.MTRANS_Y] + mYOffset;
                 int w = frame.width();
                 int h = frame.height();
                 mShownFrame.set(x, y, x+w, y+h);
@@ -6550,6 +6819,9 @@
             }
 
             mShownFrame.set(mFrame);
+            if (mXOffset != 0 || mYOffset != 0) {
+                mShownFrame.offset(mXOffset, mYOffset);
+            }
             mShownAlpha = mAlpha;
             mDsDx = 1;
             mDtDx = 0;
@@ -6711,7 +6983,7 @@
 
         boolean isFullscreen(int screenWidth, int screenHeight) {
             return mFrame.left <= 0 && mFrame.top <= 0 &&
-                mFrame.right >= screenWidth && mFrame.bottom >= screenHeight;
+                    mFrame.right >= screenWidth && mFrame.bottom >= screenHeight;
         }
 
         void removeLocked() {
@@ -6801,8 +7073,11 @@
                 pw.print(prefix); pw.print("mAttachedWindow="); pw.print(mAttachedWindow);
                         pw.print(" mLayoutAttached="); pw.println(mLayoutAttached);
             }
-            if (mIsImWindow) {
-                pw.print(prefix); pw.print("mIsImWindow="); pw.println(mIsImWindow);
+            if (mIsImWindow || mIsWallpaper || mIsFloatingLayer) {
+                pw.print(prefix); pw.print("mIsImWindow="); pw.print(mIsImWindow);
+                        pw.print(" mIsWallpaper="); pw.print(mIsWallpaper);
+                        pw.print(" mIsFloatingLayer="); pw.print(mIsFloatingLayer);
+                        pw.print(" mWallpaperVisible="); pw.println(mWallpaperVisible);
             }
             pw.print(prefix); pw.print("mBaseLayer="); pw.print(mBaseLayer);
                     pw.print(" mSubLayer="); pw.print(mSubLayer);
@@ -6834,9 +7109,11 @@
                         pw.print(" mAttachedHidden="); pw.println(mAttachedHidden);
             }
             pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth);
-                    pw.print(" h="); pw.print(mRequestedHeight);
-                    pw.print(" x="); pw.print(mReqXPos);
-                    pw.print(" y="); pw.println(mReqYPos);
+                    pw.print(" h="); pw.println(mRequestedHeight);
+            if (mXOffset != 0 || mYOffset != 0) {
+                pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset);
+                        pw.print(" y="); pw.println(mYOffset);
+            }
             pw.print(prefix); pw.print("mGivenContentInsets=");
                     mGivenContentInsets.printShortString(pw);
                     pw.print(" mGivenVisibleInsets=");
@@ -6904,6 +7181,10 @@
                 pw.print(prefix); pw.print("mHScale="); pw.print(mHScale);
                         pw.print(" mVScale="); pw.println(mVScale);
             }
+            if (mWallpaperX != 0 || mWallpaperY != 0) {
+                pw.print(prefix); pw.print("mWallpaperX="); pw.print(mWallpaperX);
+                        pw.print(" mWallpaperY="); pw.println(mWallpaperY);
+            }
         }
 
         @Override
@@ -7088,6 +7369,9 @@
                 if (w == mInputMethodTarget) {
                     setInputMethodAnimLayerAdjustment(adj);
                 }
+                if (w == mWallpaperTarget) {
+                    setWallpaperAnimLayerAdjustmentLocked(adj);
+                }
             }
         }
 
@@ -7838,7 +8122,7 @@
 
         for (i=0; i<N; i++) {
             WindowState w = (WindowState)mWindows.get(i);
-            if (w.mBaseLayer == curBaseLayer || w.mIsImWindow) {
+            if (w.mBaseLayer == curBaseLayer || w.mIsFloatingLayer) {
                 curLayer += WINDOW_LAYER_MULTIPLIER;
                 w.mLayer = curLayer;
             } else {
@@ -7854,6 +8138,8 @@
             }
             if (w.mIsImWindow) {
                 w.mAnimLayer += mInputMethodAnimLayerAdjustment;
+            } else if (w.mIsWallpaper) {
+                w.mAnimLayer += mWallpaperAnimLayerAdjustment;
             }
             if (DEBUG_LAYERS) Log.v(TAG, "Assign layer " + w + ": "
                     + w.mAnimLayer);
@@ -8242,6 +8528,7 @@
                         // This has changed the visibility of windows, so perform
                         // a new layout to get them all up-to-date.
                         mLayoutNeeded = true;
+                        adjustWallpaperWindowsLocked();
                         if (!moveInputMethodWindowsIfNeededLocked(true)) {
                             assignLayersLocked();
                         }
@@ -8534,7 +8821,8 @@
                     }
 
                     boolean opaqueDrawn = w.isOpaqueDrawn();
-                    if (opaqueDrawn && w.isFullscreen(dw, dh)) {
+                    if ((opaqueDrawn && w.isFullscreen(dw, dh))
+                            || attrs.type == TYPE_WALLPAPER) {
                         // This window completely covers everything behind it,
                         // so we want to leave all of them as unblurred (for
                         // performance reasons).
@@ -8701,6 +8989,9 @@
             WindowToken token = mExitingTokens.get(i);
             if (!token.hasVisible) {
                 mExitingTokens.remove(i);
+                if (token.windowType == TYPE_WALLPAPER) {
+                    mWallpaperTokens.remove(token);
+                }
             }
         }
 
@@ -9123,6 +9414,16 @@
                             pw.println(mTokenList.get(i));
                 }
             }
+            if (mWallpaperTokens.size() > 0) {
+                pw.println(" ");
+                pw.println("  Wallpaper tokens:");
+                for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
+                    WindowToken token = mWallpaperTokens.get(i);
+                    pw.print("  Wallpaper #"); pw.print(i);
+                            pw.print(' '); pw.print(token); pw.println(':');
+                    token.dump(pw, "    ");
+                }
+            }
             if (mAppTokens.size() > 0) {
                 pw.println(" ");
                 pw.println("  Application tokens in Z order:");
@@ -9178,7 +9479,9 @@
                 pw.print( "  no DimAnimator ");
             }
             pw.print("  mInputMethodAnimLayerAdjustment=");
-                    pw.println(mInputMethodAnimLayerAdjustment);
+                    pw.print(mInputMethodAnimLayerAdjustment);
+                    pw.print("  mWallpaperAnimLayerAdjustment=");
+                    pw.println(mWallpaperAnimLayerAdjustment);
             pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
                     pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
                     pw.print(" mAppsFreezingScreen="); pw.println(mAppsFreezingScreen);
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 4ed0a5c6..a877c73 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -22,6 +22,7 @@
 import android.net.Uri;
 import android.os.SystemProperties;
 import android.provider.Contacts;
+import android.provider.ContactsContract;
 import android.text.Editable;
 import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
@@ -129,15 +130,23 @@
         }
 
         String type = intent.resolveType(context);
+        String phoneColumn = null;
 
-        Cursor c = context.getContentResolver().query(
-                uri, new String[]{ Contacts.People.Phones.NUMBER },
-                null, null, null);
+        // Correctly read out the phone entry based on requested provider
+        final String authority = uri.getAuthority();
+        if (Contacts.AUTHORITY.equals(authority)) {
+            phoneColumn = Contacts.People.Phones.NUMBER;
+        } else if (ContactsContract.AUTHORITY.equals(authority)) {
+            phoneColumn = ContactsContract.CommonDataKinds.Phone.NUMBER;
+        }
+
+        final Cursor c = context.getContentResolver().query(uri, new String[] {
+            phoneColumn
+        }, null, null, null);
         if (c != null) {
             try {
                 if (c.moveToFirst()) {
-                    number = c.getString(
-                            c.getColumnIndex(Contacts.People.Phones.NUMBER));
+                    number = c.getString(c.getColumnIndex(phoneColumn));
                 }
             } finally {
                 c.close();
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index c074cb8..a3f1ad8 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -96,10 +96,11 @@
     public static final int EVENT_CLEAN_UP_CONNECTION = 34;
 
     //***** Constants
-    protected static final int RECONNECT_DELAY_INITIAL_MILLIS = 5 * 1000;
 
-    /** Cap out with 30 min retry interval. */
-    protected static final int RECONNECT_DELAY_MAX_MILLIS = 30 * 60 * 1000;
+    /** Retry configuration: A doubling of retry times from 5secs to 30minutes */
+    protected static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000,"
+        + "5000,10000,20000,40000,80000:5000,160000:5000,"
+        + "320000:5000,640000:5000,1280000:5000,1800000:5000";
 
     /** Slow poll when attempting connection recovery. */
     protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
index e8095e1..461b694 100644
--- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java
+++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
@@ -183,15 +183,9 @@
         }
 
         int headerBits = (header.length + 1) * 8;
-        int headerSeptets = headerBits / 7;
-        headerSeptets += (headerBits % 7) > 0 ? 1 : 0;
+        int headerSeptets = (headerBits + 6) / 7;
 
-        int sz = data.length();
-        int septetCount;
-        septetCount = countGsmSeptets(data, true) + headerSeptets;
-
-        byte[] ret = stringToGsm7BitPacked(data, 0, septetCount,
-                (headerSeptets*7), true);
+        byte[] ret = stringToGsm7BitPacked(data, headerSeptets, true);
 
         // Paste in the header
         ret[1] = (byte)header.length;
@@ -215,7 +209,7 @@
      */
     public static byte[] stringToGsm7BitPacked(String data)
             throws EncodeException {
-        return stringToGsm7BitPacked(data, 0, -1, 0, true);
+        return stringToGsm7BitPacked(data, 0, true);
     }
 
     /**
@@ -228,58 +222,37 @@
      * septets.
      *
      * @param data the text to convert to septets
-     * @param dataOffset the character offset in data to start the encoding from
-     * @param maxSeptets the maximum number of septets to convert, or -1 for no
-     *  enforced maximum.
-     * @param startingBitOffset the number of padding bits to put before
-     *  the start of the first septet at the begining of the array
+     * @param startingSeptetOffset the number of padding septets to put before
+     *  the character data at the begining of the array
      * @param throwException If true, throws EncodeException on invalid char.
      *   If false, replaces unencodable char with GSM alphabet space char.
      *
      * @throws EncodeException if String is too large to encode
      */
-    public static byte[] stringToGsm7BitPacked(String data, int dataOffset,
-            int maxSeptets, int startingBitOffset, boolean throwException)
-            throws EncodeException {
-
-        int sz = data.length();
-        int septetCount;
-        if (maxSeptets == -1) {
-            septetCount = countGsmSeptets(data, true);
-        } else {
-            septetCount = maxSeptets;
+    public static byte[] stringToGsm7BitPacked(String data, int startingSeptetOffset,
+            boolean throwException) throws EncodeException {
+        int dataLen = data.length();
+        int septetCount = countGsmSeptets(data, throwException) + startingSeptetOffset;
+        if (septetCount > 255) {
+            throw new EncodeException("Payload cannot exceed 255 septets");
         }
-
-        if(septetCount > 0xff) {
-            throw new EncodeException("Payload cannot exceed " + Short.MAX_VALUE
-                    + " septets");
-        }
-
-        // Enough for all the septets and the length 2 byte prefix
-        byte[] ret = new byte[1 + (((septetCount * 7) + 7) / 8)];
-
-        int bitOffset = startingBitOffset;
-        int septets = startingBitOffset/7;
-        for (int i = dataOffset; i < sz && septets < septetCount; i++, bitOffset += 7) {
+        int byteCount = ((septetCount * 7) + 7) / 8;
+        byte[] ret = new byte[byteCount + 1];  // Include space for one byte length prefix.
+        for (int i = 0, septets = startingSeptetOffset, bitOffset = startingSeptetOffset * 7;
+                 i < dataLen && septets < septetCount;
+                 i++, bitOffset += 7) {
             char c = data.charAt(i);
-
             int v = GsmAlphabet.charToGsm(c, throwException);
             if (v == GSM_EXTENDED_ESCAPE) {
-                // Lookup the extended char
-                v = GsmAlphabet.charToGsmExtended(c);
-
+                v = GsmAlphabet.charToGsmExtended(c);  // Lookup the extended char.
                 packSmsChar(ret, bitOffset, GSM_EXTENDED_ESCAPE);
                 bitOffset += 7;
                 septets++;
             }
-
             packSmsChar(ret, bitOffset, v);
             septets++;
         }
-
-        // See check for > 0xff above
-        ret[0] = (byte)septets;
-
+        ret[0] = (byte) (septetCount);  // Validated by check above.
         return ret;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 769226e..86ea12b 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -542,6 +542,20 @@
     void unregisterForCdmaOtaStatusChange(Handler h);
 
     /**
+     * Registration point for subscription info ready
+     * @param h handler to notify
+     * @param what what code of message when delivered
+     * @param obj placed in Message.obj
+     */
+    public void registerForSubscriptionInfoReady(Handler h, int what, Object obj);
+
+    /**
+     * Unregister for notifications for subscription info
+     * @param h Handler to be removed from the registrant list.
+     */
+    public void unregisterForSubscriptionInfoReady(Handler h);
+
+    /**
      * Returns SIM record load state. Use
      * <code>getSimCard().registerForReady()</code> for change notification.
      *
@@ -1366,6 +1380,13 @@
     String getCdmaMin();
 
     /**
+     * Check if subscription data has been assigned to mMin
+     *
+     * return true if MIN info is ready; false otherwise.
+     */
+    boolean isMinInfoReady();
+
+    /**
      *  Retrieves PRL Version for CDMA phones
      */
     String getCdmaPrlVersion();
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index fbda221..b279527 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -59,10 +59,13 @@
     private static final String LOG_TAG = "PHONE";
     private static final boolean LOCAL_DEBUG = true;
 
-    // Key used to read and write the saved network selection value
+    // Key used to read and write the saved network selection numeric value
     public static final String NETWORK_SELECTION_KEY = "network_selection_key";
+    // Key used to read and write the saved network selection operator name
+    public static final String NETWORK_SELECTION_NAME_KEY = "network_selection_name_key";
 
- // Key used to read/write "disable data connection on boot" pref (used for testing)
+
+    // Key used to read/write "disable data connection on boot" pref (used for testing)
     public static final String DATA_DISABLED_ON_BOOT_KEY = "disabled_on_boot_key";
 
     //***** Event Constants
@@ -698,6 +701,12 @@
         return null;
     }
 
+    public boolean isMinInfoReady() {
+        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
+        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+        return false;
+    }
+
     public String getCdmaPrlVersion(){
         //  This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
         Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
@@ -724,6 +733,16 @@
         Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
     }
 
+    public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
+        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
+        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+    }
+
+    public void unregisterForSubscriptionInfoReady(Handler h) {
+        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
+        Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+    }
+
     public  boolean isOtaSpNumber(String dialStr) {
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
         Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index 30d56da..f2568c1 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -315,6 +315,14 @@
          mActivePhone.unregisterForCdmaOtaStatusChange(h);
     }
 
+    public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
+        mActivePhone.registerForSubscriptionInfoReady(h, what, obj);
+    }
+
+    public void unregisterForSubscriptionInfoReady(Handler h) {
+        mActivePhone.unregisterForSubscriptionInfoReady(h);
+    }
+
     public boolean getIccRecordsLoaded() {
         return mActivePhone.getIccRecordsLoaded();
     }
@@ -419,6 +427,10 @@
         return mActivePhone.getCdmaMin();
     }
 
+    public boolean isMinInfoReady() {
+        return mActivePhone.isMinInfoReady();
+    }
+
     public String getCdmaPrlVersion() {
         return mActivePhone.getCdmaPrlVersion();
     }
diff --git a/telephony/java/com/android/internal/telephony/RetryManager.java b/telephony/java/com/android/internal/telephony/RetryManager.java
new file mode 100644
index 0000000..242b2cd
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/RetryManager.java
@@ -0,0 +1,383 @@
+/**
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.util.Log;
+import android.util.Pair;
+import android.text.TextUtils;
+
+import java.util.Random;
+import java.util.ArrayList;
+
+/**
+ * Retry manager allows a simple way to declare a series of
+ * retires timeouts. After creating a RetryManager the configure
+ * method is used to define the sequence. A simple linear series
+ * may be initialized using configure with three integer parameters
+ * The other configure method allows a series to be declared using
+ * a string.
+ *<p>
+ * The format of the configuration string is a series of parameters
+ * separated by a comma. There are two name value pair parameters plus a series
+ * of delay times. The units of of these delay times is unspecified.
+ * The name value pairs which may be specified are:
+ *<ul>
+ *<li>max_retries=<value>
+ *<li>default_randomizationTime=<value>
+ *</ul>
+ *<p>
+ * max_retries is the number of times that incrementRetryCount
+ * maybe called before isRetryNeeded will return false.
+ *
+ * default_randomizationTime will be used as the randomizationTime
+ * for delay times which have no supplied randomizationTime. If
+ * default_randomizationTime is not defined it defaults to 0.
+ *<p>
+ * The other parameters define The series of delay times and each
+ * may have an optional randomization value separated from the
+ * delay time by a colon.
+ *<p>
+ * Examples:
+ * <ul>
+ * <li>3 retires with no randomization value which means its 0:
+ * <ul><li><code>"1000, 2000, 3000"</code></ul>
+ *
+ * <li>10 retires with a 500 default randomization value for each and
+ * the 4..10 retries all using 3000 as the delay:
+ * <ul><li><code>"max_retries=10, default_randomization=500, 1000, 2000, 3000"</code></ul>
+ *
+ * <li>4 retires with a 100ms default randomization value for the first 2 values and
+ * the other two having specified values of 500ms:
+ * <ul><li><code>"default_randomization=100, 1000, 2000, 4000:500, 5000:500"</code></ul>
+ * </ul>
+ *
+ * {@hide}
+ */
+public class RetryManager {
+    static public final String LOG_TAG = "RetryManager";
+    static public final boolean DBG = false;
+    static public final int RETRYIES_NOT_STARTED = 0;
+    static public final int RETRYIES_ON_GOING = 1;
+    static public final int RETRYIES_COMPLETED = 2;
+
+    /**
+     * Retry record with times in milli-seconds
+     */
+    private static class RetryRec {
+        RetryRec(int delayTime, int randomizationTime) {
+            mDelayTime = delayTime;
+            mRandomizationTime = randomizationTime;
+        }
+
+        int mDelayTime;
+        int mRandomizationTime;
+    }
+
+    /** The array of retry records */
+    private ArrayList<RetryRec> mRetryArray = new ArrayList<RetryRec>();
+
+    /** When true isRetryNeeded() will always return true */
+    private boolean mRetryForever;
+
+    /**
+     * The maximum number of retries to attempt before
+     * isRetryNeeded returns false
+     */
+    private int mMaxRetryCount;
+
+    /** The current number of retires */
+    private int mRetryCount;
+
+    /** Random number generator */
+    private Random rng = new Random();
+
+    /** Constructor */
+    public RetryManager() {
+        if (DBG) log("constructor");
+    }
+
+    /**
+     * Configure for a simple linear sequence of times plus
+     * a random value.
+     *
+     * @param maxRetryCount is the maximum number of retries
+     *        before isRetryNeeded returns false.
+     * @param retryTime is a time that will be returned by getRetryTime.
+     * @param randomizationTime a random value between 0 and
+     *        randomizationTime will be added to retryTime. this
+     *        parameter may be 0.
+     * @return true if successfull
+     */
+    public boolean configure(int maxRetryCount, int retryTime, int randomizationTime) {
+        Pair<Boolean, Integer> value;
+
+        if (DBG) log("configure: " + maxRetryCount + ", " + retryTime + "," + randomizationTime);
+
+        if (!validateNonNegativeInt("maxRetryCount", maxRetryCount)) {
+            return false;
+        }
+
+        if (!validateNonNegativeInt("retryTime", retryTime)) {
+            return false;
+        }
+
+        if (!validateNonNegativeInt("randomizationTime", randomizationTime)) {
+            return false;
+        }
+
+        mMaxRetryCount = maxRetryCount;
+        resetRetryCount();
+        mRetryArray.clear();
+        mRetryArray.add(new RetryRec(retryTime, randomizationTime));
+
+        return true;
+    }
+
+    /**
+     * Configure for using string which allow arbitary
+     * sequences of times. See class comments for the
+     * string format.
+     *
+     * @return true if successfull
+     */
+    public boolean configure(String configStr) {
+        if (DBG) log("configure: '" + configStr + "'");
+
+        if (!TextUtils.isEmpty(configStr)) {
+            int defaultRandomization = 0;
+
+            if (DBG) log("configure: not empty");
+
+            mMaxRetryCount = 0;
+            resetRetryCount();
+            mRetryArray.clear();
+
+            String strArray[] = configStr.split(",");
+            for (int i = 0; i < strArray.length; i++) {
+                if (DBG) log("configure: strArray[" + i + "]='" + strArray[i] + "'");
+                Pair<Boolean, Integer> value;
+                String splitStr[] = strArray[i].split("=", 2);
+                splitStr[0] = splitStr[0].trim();
+                if (DBG) log("configure: splitStr[0]='" + splitStr[0] + "'");
+                if (splitStr.length > 1) {
+                    splitStr[1] = splitStr[1].trim();
+                    if (DBG) log("configure: splitStr[1]='" + splitStr[1] + "'");
+                    if (TextUtils.equals(splitStr[0], "default_randomization")) {
+                        value = parseNonNegativeInt(splitStr[0], splitStr[1]);
+                        if (!value.first) return false;
+                        defaultRandomization = value.second;
+                    } else if (TextUtils.equals(splitStr[0], "max_retries")) {
+                        value = parseNonNegativeInt(splitStr[0], splitStr[1]);
+                        if (!value.first) return false;
+                        mMaxRetryCount = value.second;
+                    } else {
+                        Log.e(LOG_TAG, "Unrecognized configuration name value pair: "
+                                        + strArray[i]);
+                        return false;
+                    }
+                } else {
+                    /**
+                     * Assume a retry time with an optional randomization value
+                     * following a ":"
+                     */
+                    splitStr = strArray[i].split(":", 2);
+                    splitStr[0] = splitStr[0].trim();
+                    RetryRec rr = new RetryRec(0, 0);
+                    value = parseNonNegativeInt("delayTime", splitStr[0]);
+                    if (!value.first) return false;
+                    rr.mDelayTime = value.second;
+
+                    // Check if optional randomization value present
+                    if (splitStr.length > 1) {
+                        splitStr[1] = splitStr[1].trim();
+                        if (DBG) log("configure: splitStr[1]='" + splitStr[1] + "'");
+                        value = parseNonNegativeInt("randomizationTime", splitStr[1]);
+                        if (!value.first) return false;
+                        rr.mRandomizationTime = value.second;
+                    } else {
+                        rr.mRandomizationTime = defaultRandomization;
+                    }
+                    mRetryArray.add(rr);
+                }
+            }
+            if (mRetryArray.size() > mMaxRetryCount) {
+                mMaxRetryCount = mRetryArray.size();
+                if (DBG) log("configure: setting mMaxRetryCount=" + mMaxRetryCount);
+            }
+            if (DBG) log("configure: true");
+            return true;
+        } else {
+            if (DBG) log("configure: false it's empty");
+            return false;
+        }
+    }
+
+    /**
+     * Report whether data reconnection should be retried
+     *
+     * @return {@code true} if the max retires has not been reached. {@code
+     *         false} otherwise.
+     */
+    public boolean isRetryNeeded() {
+        boolean retVal = mRetryForever || (mRetryCount < mMaxRetryCount);
+        if (DBG) log("isRetryNeeded: " + retVal);
+        return retVal;
+    }
+
+    /**
+     * Return the timer that should be used to trigger the data reconnection
+     */
+    public int getRetryTimer() {
+        int index;
+        if (mRetryCount < mRetryArray.size()) {
+            index = mRetryCount;
+        } else {
+            index = mRetryArray.size() - 1;
+        }
+
+        int retVal;
+        if ((index >= 0) && (index < mRetryArray.size())) {
+            retVal = mRetryArray.get(index).mDelayTime + nextRandomizationTime(index);
+        } else {
+            retVal = 0;
+        }
+
+        if (DBG) log("getRetryTimer: " + retVal);
+        return retVal;
+    }
+
+    /**
+     * @return retry count
+     */
+    public int getRetryCount() {
+        if (DBG) log("getRetryCount: " + mRetryCount);
+        return mRetryCount;
+    }
+
+    /**
+     * Increase the retry counter, does not change retry forever.
+     */
+    public void increaseRetryCount() {
+        mRetryCount++;
+        if (mRetryCount > mMaxRetryCount) {
+            mRetryCount = mMaxRetryCount;
+        }
+        if (DBG) log("increseRetryCount: " + mRetryCount);
+    }
+
+    /**
+     * Set retry count to the specified value
+     * and turns off retrying forever.
+     */
+    public void setRetryCount(int count) {
+        mRetryCount = count;
+        if (mRetryCount > mMaxRetryCount) {
+            mRetryCount = mMaxRetryCount;
+        }
+
+        if (mRetryCount < 0) {
+            mRetryCount = 0;
+        }
+
+        mRetryForever = false;
+        if (DBG) log("setRetryCount: " + mRetryCount);
+    }
+
+    /**
+     * Reset network re-registration indicator and clear the data-retry counter
+     * and turns off retrying forever.
+     */
+    public void resetRetryCount() {
+        mRetryCount = 0;
+        mRetryForever = false;
+        if (DBG) log("resetRetryCount: " + mRetryCount);
+    }
+
+    /**
+     * Retry forever using last timeout time.
+     */
+    public void retryForeverUsingLastTimeout() {
+        mRetryCount = mMaxRetryCount;
+        mRetryForever = true;
+        if (DBG) log("retryForeverUsingLastTimeout: " + mRetryForever + ", " + mRetryCount);
+    }
+
+    /**
+     * @return true if retrying forever
+     */
+    public boolean isRetryForever() {
+        if (DBG) log("isRetryForever: " + mRetryForever);
+        return mRetryForever;
+    }
+
+    /**
+     * Parse an integer validating the value is not negative.
+     *
+     * @param name
+     * @param stringValue
+     * @return Pair.first == true if stringValue an integer >= 0
+     */
+    private Pair<Boolean, Integer> parseNonNegativeInt(String name, String stringValue) {
+        int value;
+        Pair<Boolean, Integer> retVal;
+        try {
+            value = Integer.parseInt(stringValue);
+            retVal = new Pair<Boolean, Integer>(validateNonNegativeInt(name, value), value);
+        } catch (NumberFormatException e) {
+            Log.e(LOG_TAG, name + " bad value: " + stringValue, e);
+            retVal = new Pair<Boolean, Integer>(false, 0);
+        }
+        if (DBG) log("parseNonNetativeInt: " + name + ", " + stringValue + ", "
+                    + retVal.first + ", " + retVal.second);
+        return retVal;
+    }
+
+    /**
+     * Validate an integer is >= 0 and logs an error if not
+     *
+     * @param name
+     * @param value
+     * @return Pair.first
+     */
+    private boolean validateNonNegativeInt(String name, int value) {
+        boolean retVal;
+        if (value < 0) {
+            Log.e(LOG_TAG, name + " bad value: is < 0");
+            retVal = false;
+        } else {
+            retVal = true;
+        }
+        if (DBG) log("validateNonNegative: " + name + ", " + value + ", " + retVal);
+        return retVal;
+    }
+
+    /**
+     * Return next random number for the index
+     */
+    private int nextRandomizationTime(int index) {
+        int randomTime = mRetryArray.get(index).mRandomizationTime;
+        if (randomTime == 0) {
+            return 0;
+        } else {
+            return rng.nextInt(randomTime);
+        }
+    }
+
+    private void log(String s) {
+        Log.d(LOG_TAG, s);
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 8a1e928..60e0a44 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -115,4 +115,9 @@
      */
     static final String PROPERTY_OTASP_NUM_SCHEMA = "ro.cdma.otaspnumschema";
 
+    /**
+     * Disable all calls including Emergency call when it set to true.
+     */
+    static final String PROPERTY_DISABLE_CALL = "ro.telephony.disable-call";
+
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 7b3ff5e..522fa1d 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -441,6 +441,10 @@
         return mSST.getCdmaMin();
     }
 
+    public boolean isMinInfoReady() {
+        return mSST.isMinInfoReady();
+    }
+
     public void getCallWaiting(Message onComplete) {
         mCM.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
     }
@@ -556,6 +560,14 @@
         mCM.unregisterForCdmaOtaProvision(h);
     }
 
+    public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
+        mSST.registerForSubscriptionInfoReady(h, what, obj);
+    }
+
+    public void unregisterForSubscriptionInfoReady(Handler h) {
+        mSST.unregisterForSubscriptionInfoReady(h);
+    }
+
     public void setOnEcbModeExitResponse(Handler h, int what, Object obj) {
         mECMExitRespRegistrant = new Registrant (h, what, obj);
     }
@@ -777,9 +789,6 @@
             Intent intent = new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS);
             ActivityManagerNative.broadcastStickyIntent(intent, null);
             return false;
-        } else if ((mCT.state == Phone.State.OFFHOOK) && mCT.isInEmergencyCall()) {
-            // Do not allow data call to be enabled when emergency call is going on
-            return false;
         } else {
             return mDataConnection.setDataEnabled(true);
         }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
index 005db47..be4763c 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -80,7 +80,6 @@
     int pendingCallClirMode;
     Phone.State state = Phone.State.IDLE;
 
-    private boolean mIsInEmergencyCall = false;
 
 //    boolean needsPoll;
 
@@ -211,9 +210,6 @@
             // Always unmute when initiating a new call
             setMute(false);
 
-            // Check data call
-            disableDataCallInEmergencyCall(dialString);
-
             String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
             if(inEcm.equals("false")) {
                 cm.dial(pendingMO.address, clirMode, obtainCompleteMessage());
@@ -240,9 +236,6 @@
     private Connection
     dialThreeWay (String dialString) {
         if (!foregroundCall.isIdle()) {
-            // Check data call
-            disableDataCallInEmergencyCall(dialString);
-
             // Attach the new connection to foregroundCall
             pendingMO = new CdmaConnection(phone.getContext(),
                                 dialString, this, foregroundCall);
@@ -328,13 +321,16 @@
     canDial() {
         boolean ret;
         int serviceState = phone.getServiceState().getState();
+        String disableCall = SystemProperties.get(
+                TelephonyProperties.PROPERTY_DISABLE_CALL, "false");
 
-        ret = (serviceState != ServiceState.STATE_POWER_OFF) &&
-                pendingMO == null
+        ret = (serviceState != ServiceState.STATE_POWER_OFF)
+                && pendingMO == null
                 && !ringingCall.isRinging()
+                && !disableCall.equals("true")
                 && (!foregroundCall.getState().isAlive()
-                || (foregroundCall.getState() == CdmaCall.State.ACTIVE)
-                || !backgroundCall.getState().isAlive());
+                    || (foregroundCall.getState() == CdmaCall.State.ACTIVE)
+                    || !backgroundCall.getState().isAlive());
 
         return ret;
     }
@@ -536,9 +532,6 @@
                     }
                 }
                 foregroundCall.setGeneric(false);
-
-                mIsInEmergencyCall = false;
-
                 // Dropped connections are removed from the CallTracker
                 // list but kept in the Call list
                 connections[i] = null;
@@ -978,26 +971,6 @@
         }
     }
 
-    /**
-     * Disable data call when emergency call is connected
-     */
-    private void disableDataCallInEmergencyCall(String dialString) {
-        if (PhoneNumberUtils.isEmergencyNumber(dialString)) {
-            phone.disableDataConnectivity();
-            mIsInEmergencyCall = true;
-        }
-    }
-
-    /**
-     * Check if current call is in emergency call
-     *
-     * @return true if it is in emergency call
-     *         false if it is not in emergency call
-     */
-    boolean isInEmergencyCall() {
-        return mIsInEmergencyCall;
-    }
-
     protected void log(String msg) {
         Log.d(LOG_TAG, "[CdmaCallTracker] " + msg);
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index c3818f5..38bc24d 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -31,6 +31,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.preference.PreferenceManager;
 import android.provider.Checkin;
 import android.telephony.ServiceState;
@@ -45,6 +46,7 @@
 import com.android.internal.telephony.DataConnection;
 import com.android.internal.telephony.DataConnection.FailCause;
 import com.android.internal.telephony.DataConnectionTracker;
+import com.android.internal.telephony.RetryManager;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.TelephonyEventLog;
 
@@ -61,8 +63,6 @@
 
     // Indicates baseband will not auto-attach
     private boolean noAutoAttach = false;
-    long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
-    private boolean mReregisterOnReconnectFailure = false;
     private boolean mIsScreenOn = true;
 
     //useful for debugging
@@ -76,6 +76,9 @@
     /** Currently active CdmaDataConnection */
     private CdmaDataConnection mActiveDataConnection;
 
+    /** Manage the behavior of data retry after failure */
+    private final RetryManager mRetryMgr = new RetryManager();
+
     /** Defined cdma connection profiles */
     private static final int EXTERNAL_NETWORK_DEFAULT_ID = 0;
     private static final int EXTERNAL_NETWORK_NUM_TYPES  = 1;
@@ -183,10 +186,19 @@
         dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID] =
                 !sp.getBoolean(CDMAPhone.DATA_DISABLED_ON_BOOT_KEY, false);
         noAutoAttach = !dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID];
+
+        if (!mRetryMgr.configure(SystemProperties.get("ro.cdma.data_retry_config"))) {
+            if (!mRetryMgr.configure(DEFAULT_DATA_RETRY_CONFIG)) {
+                // Should never happen, log an error and default to a simple linear sequence.
+                Log.e(LOG_TAG, "Could not configure using DEFAULT_DATA_RETRY_CONFIG="
+                        + DEFAULT_DATA_RETRY_CONFIG);
+                mRetryMgr.configure(20, 2000, 1000);
+            }
+        }
     }
 
     public void dispose() {
-        //Unregister from all events
+        // Unregister from all events
         phone.mCM.unregisterForAvailable(this);
         phone.mCM.unregisterForOffOrNotAvailable(this);
         mCdmaPhone.mRuimRecords.unregisterForRecordsLoaded(this);
@@ -459,9 +471,7 @@
         setState(State.CONNECTED);
         phone.notifyDataConnection(reason);
         startNetStatPoll();
-        // reset reconnect timer
-        nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
-        mReregisterOnReconnectFailure = false;
+        mRetryMgr.resetRetryCount();
     }
 
     private void resetPollStats() {
@@ -617,21 +627,13 @@
 
     private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) {
         if (state == State.FAILED) {
-            if (nextReconnectDelay > RECONNECT_DELAY_MAX_MILLIS) {
-                if (mReregisterOnReconnectFailure) {
-                    // We have already tried to re-register to the network.
-                    // This might be a problem with the data network.
-                    nextReconnectDelay = RECONNECT_DELAY_MAX_MILLIS;
-                } else {
-                    // Try to Re-register to the network.
-                    Log.d(LOG_TAG, "PDP activate failed, Reregistering to the network");
-                    mReregisterOnReconnectFailure = true;
-                    mCdmaPhone.mSST.reRegisterNetwork(null);
-                    nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
-                    return;
-                }
-            }
-
+            /**
+             * For now With CDMA we never try to reconnect on
+             * error and instead just continue to retry
+             * at the last time until the state is changed.
+             * TODO: Make this configurable?
+             */
+            int nextReconnectDelay = mRetryMgr.getRetryTimer();
             Log.d(LOG_TAG, "Data Connection activate failed. Scheduling next attempt for "
                     + (nextReconnectDelay / 1000) + "s");
 
@@ -645,8 +647,7 @@
                     SystemClock.elapsedRealtime() + nextReconnectDelay,
                     mReconnectIntent);
 
-            // double it for next time
-            nextReconnectDelay *= 2;
+            mRetryMgr.increaseRetryCount();
 
             if (!shouldPostNotification(lastFailCauseCode)) {
                 Log.d(LOG_TAG,"NOT Posting Data Connection Unavailable notification "
@@ -723,10 +724,7 @@
      * @override com.android.internal.telephony.DataConnectionTracker
      */
     protected void onRadioOffOrNotAvailable() {
-        // Make sure our reconnect delay starts at the initial value
-        // next time the radio comes on
-        nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
-        mReregisterOnReconnectFailure = false;
+        mRetryMgr.resetRetryCount();
 
         if (phone.getSimulatedRadioControl() != null) {
             // Assume data is connected on the simulator
@@ -802,9 +800,7 @@
                 resetPollStats();
             }
         } else {
-            // reset reconnect timer
-            nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
-            mReregisterOnReconnectFailure = false;
+            mRetryMgr.resetRetryCount();
             // in case data setup was attempted when we were on a voice call
             trySetupData(Phone.REASON_VOICE_CALL_ENDED);
         }
@@ -840,7 +836,7 @@
         } else {
             if (state == State.FAILED) {
                 cleanUpConnection(false, Phone.REASON_CDMA_DATA_DETACHED);
-                nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+                mRetryMgr.resetRetryCount();
 
                 CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation());
                 int bsid = (loc != null) ? loc.getBaseStationId() : -1;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index 1f1f7c1..88cccd3 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -91,7 +91,8 @@
         int teleService = sms.getTeleService();
         boolean handled = false;
 
-        if ((sms.getUserData() == null) && (SmsEnvelope.TELESERVICE_MWI != teleService)) {
+        if ((sms.getUserData() == null) && (SmsEnvelope.TELESERVICE_MWI != teleService) &&
+            (SmsEnvelope.TELESERVICE_VMN != teleService)) {
             if (Config.LOGD) {
                 Log.d(TAG, "Received SMS without user data");
             }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 53f0274..753b5e7 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -93,6 +93,7 @@
     private int mRegistrationState = -1;
     private RegistrantList cdmaDataConnectionAttachedRegistrants = new RegistrantList();
     private RegistrantList cdmaDataConnectionDetachedRegistrants = new RegistrantList();
+    private RegistrantList cdmaForSubscriptionInfoReadyRegistrants = new RegistrantList();
 
     // Sometimes we get the NITZ time before we know what country we are in.
     // Keep the time zone information from the NITZ string so we can fix
@@ -125,6 +126,7 @@
     private int mHomeNetworkId[] = null;
     private String mMin;
     private String mPrlVersion;
+    private boolean mIsMinInfoReady = false;
 
     private boolean isEriTextLoaded = false;
     private boolean isSubscriptionFromRuim = false;
@@ -264,6 +266,25 @@
         cdmaDataConnectionDetachedRegistrants.remove(h);
     }
 
+    /**
+     * Registration point for subscription info ready
+     * @param h handler to notify
+     * @param what what code of message when delivered
+     * @param obj placed in Message.obj
+     */
+    public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
+        Registrant r = new Registrant(h, what, obj);
+        cdmaForSubscriptionInfoReadyRegistrants.add(r);
+
+        if (isMinInfoReady()) {
+            r.notifyRegistrant();
+        }
+    }
+
+    public void unregisterForSubscriptionInfoReady(Handler h) {
+        cdmaForSubscriptionInfoReadyRegistrants.remove(h);
+    }
+
     //***** Called from CDMAPhone
     public void
     getLacAndCid(Message onComplete) {
@@ -426,6 +447,13 @@
                     mMin = cdmaSubscription[3];
                     mPrlVersion = cdmaSubscription[4];
                     Log.d(LOG_TAG,"GET_CDMA_SUBSCRIPTION MDN=" + mMdn);
+                    //Notify apps subscription info is ready
+                    if (cdmaForSubscriptionInfoReadyRegistrants != null) {
+                        cdmaForSubscriptionInfoReadyRegistrants.notifyRegistrants();
+                    }
+                    if (!mIsMinInfoReady) {
+                        mIsMinInfoReady = true;
+                    }
                 } else {
                     Log.w(LOG_TAG,"error parsing cdmaSubscription params num="
                             + cdmaSubscription.length);
@@ -1545,4 +1573,13 @@
             return null;
         }
     }
+
+    /**
+     * Check if subscription data has been assigned to mMin
+     *
+     * return true if MIN info is ready; false otherwise.
+     */
+    public boolean isMinInfoReady() {
+        return mIsMinInfoReady;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
index 97f92f4..65754fc 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -455,53 +455,114 @@
         }
     }
 
-    private static int calcUdhSeptetPadding(int userDataHeaderLen) {
-        int udhBits = userDataHeaderLen * 8;
-        int udhSeptets = (udhBits + 6) / 7;
-        int paddingBits = (udhSeptets * 7) - udhBits;
-        return paddingBits;
+    private static class Gsm7bitCodingResult {
+        int septets;
+        byte[] data;
     }
 
-    private static byte[] encode7bitGsm(String msg, int paddingBits)
+    private static Gsm7bitCodingResult encode7bitGsm(String msg, int septetOffset, boolean force)
         throws CodingException
     {
         try {
             /*
              * TODO(cleanup): It would be nice if GsmAlphabet provided
              * an option to produce just the data without prepending
-             * the length.
+             * the septet count, as this function is really just a
+             * wrapper to strip that off.  Not to mention that the
+             * septet count is generally known prior to invocation of
+             * the encoder.  Note that it cannot be derived from the
+             * resulting array length, since that cannot distinguish
+             * if the last contains either 1 or 8 valid bits.
+             *
+             * TODO(cleanup): The BitwiseXStreams could also be
+             * extended with byte-wise reversed endianness read/write
+             * routines to allow a corresponding implementation of
+             * stringToGsm7BitPacked, and potentially directly support
+             * access to the main bitwise stream from encode/decode.
              */
-            byte []fullData = GsmAlphabet.stringToGsm7BitPacked(msg, 0, -1, paddingBits, true);
-            byte []data = new byte[fullData.length - 1];
-            System.arraycopy(fullData, 1, data, 0, fullData.length - 1);
-            return data;
+            byte[] fullData = GsmAlphabet.stringToGsm7BitPacked(msg, septetOffset, !force);
+            Gsm7bitCodingResult result = new Gsm7bitCodingResult();
+            result.data = new byte[fullData.length - 1];
+            System.arraycopy(fullData, 1, result.data, 0, fullData.length - 1);
+            result.septets = fullData[0];
+            return result;
         } catch (com.android.internal.telephony.EncodeException ex) {
             throw new CodingException("7bit GSM encode failed: " + ex);
         }
     }
 
+    private static void encode7bitEms(UserData uData, byte[] udhData, boolean force)
+        throws CodingException
+    {
+        int udhBytes = udhData.length + 1;  // Add length octet.
+        int udhSeptets = ((udhBytes * 8) + 6) / 7;
+        Gsm7bitCodingResult gcr = encode7bitGsm(uData.payloadStr, udhSeptets, force);
+        uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
+        uData.numFields = gcr.septets;
+        uData.payload = gcr.data;
+        uData.payload[0] = (byte)udhData.length;
+        System.arraycopy(udhData, 0, uData.payload, 1, udhData.length);
+    }
+
+    private static void encode16bitEms(UserData uData, byte[] udhData)
+        throws CodingException
+    {
+        byte[] payload = encodeUtf16(uData.payloadStr);
+        int udhBytes = udhData.length + 1;  // Add length octet.
+        int udhCodeUnits = (udhBytes + 1) / 2;
+        int udhPadding = udhBytes % 2;
+        int payloadCodeUnits = payload.length / 2;
+        uData.numFields = udhCodeUnits + payloadCodeUnits;
+        uData.payload = new byte[uData.numFields * 2];
+        uData.payload[0] = (byte)udhData.length;
+        System.arraycopy(udhData, 0, uData.payload, 1, udhData.length);
+        System.arraycopy(payload, 0, uData.payload, udhBytes + udhPadding, payload.length);
+    }
+
+    private static void encodeEmsUserDataPayload(UserData uData)
+        throws CodingException
+    {
+        byte[] headerData = SmsHeader.toByteArray(uData.userDataHeader);
+        if (uData.msgEncodingSet) {
+            if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) {
+                encode7bitEms(uData, headerData, true);
+            } else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) {
+                encode16bitEms(uData, headerData);
+            } else {
+                throw new CodingException("unsupported EMS user data encoding (" +
+                                          uData.msgEncoding + ")");
+            }
+        } else {
+            try {
+                encode7bitEms(uData, headerData, false);
+            } catch (CodingException ex) {
+                encode16bitEms(uData, headerData);
+            }
+        }
+    }
+
     private static void encodeUserDataPayload(UserData uData)
         throws CodingException
     {
-        // TODO(cleanup): UDH can only occur in EMS mode, meaning
-        // encapsulation of GSM encoding, and so the logic here should
-        // be refactored to more cleanly reflect this constraint.
+        if ((uData.payloadStr == null) && (uData.msgEncoding != UserData.ENCODING_OCTET)) {
+            Log.e(LOG_TAG, "user data with null payloadStr");
+            uData.payloadStr = "";
+        }
 
-        byte[] headerData = null;
-        if (uData.userDataHeader != null) headerData = SmsHeader.toByteArray(uData.userDataHeader);
-        int headerDataLen = (headerData == null) ? 0 : headerData.length + 1;  // + length octet
+        if (uData.userDataHeader != null) {
+            encodeEmsUserDataPayload(uData);
+            return;
+        }
 
-        byte[] payloadData;
-        int codeUnitCount;
         if (uData.msgEncodingSet) {
             if (uData.msgEncoding == UserData.ENCODING_OCTET) {
                 if (uData.payload == null) {
                     Log.e(LOG_TAG, "user data with octet encoding but null payload");
-                    payloadData = new byte[0];
-                    codeUnitCount = 0;
+                    uData.payload = new byte[0];
+                    uData.numFields = 0;
                 } else {
-                    payloadData = uData.payload;
-                    codeUnitCount = uData.payload.length;
+                    uData.payload = uData.payload;
+                    uData.numFields = uData.payload.length;
                 }
             } else {
                 if (uData.payloadStr == null) {
@@ -509,65 +570,48 @@
                     uData.payloadStr = "";
                 }
                 if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) {
-                    int paddingBits = calcUdhSeptetPadding(headerDataLen);
-                    payloadData = encode7bitGsm(uData.payloadStr, paddingBits);
-                    codeUnitCount = ((payloadData.length + headerDataLen) * 8) / 7;
+                    Gsm7bitCodingResult gcr = encode7bitGsm(uData.payloadStr, 0, true);
+                    uData.payload = gcr.data;
+                    uData.numFields = gcr.septets;
                 } else if (uData.msgEncoding == UserData.ENCODING_7BIT_ASCII) {
-                    payloadData = encode7bitAscii(uData.payloadStr, true);
-                    codeUnitCount = uData.payloadStr.length();
+                    uData.payload = encode7bitAscii(uData.payloadStr, true);
+                    uData.numFields = uData.payloadStr.length();
                 } else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) {
-                    payloadData = encodeUtf16(uData.payloadStr);
-                    codeUnitCount = uData.payloadStr.length();
+                    uData.payload = encodeUtf16(uData.payloadStr);
+                    uData.numFields = uData.payloadStr.length();
                 } else {
                     throw new CodingException("unsupported user data encoding (" +
                                               uData.msgEncoding + ")");
                 }
             }
         } else {
-            if (uData.payloadStr == null) {
-                Log.e(LOG_TAG, "user data with null payloadStr");
-                uData.payloadStr = "";
-            }
             try {
-                if (headerData == null) {
-                    payloadData = encode7bitAscii(uData.payloadStr, false);
-                    codeUnitCount = uData.payloadStr.length();
-                    uData.msgEncoding = UserData.ENCODING_7BIT_ASCII;
-                } else {
-                    // If there is a header, we are in EMS mode, in
-                    // which case we use GSM encodings.
-                    int paddingBits = calcUdhSeptetPadding(headerDataLen);
-                    payloadData = encode7bitGsm(uData.payloadStr, paddingBits);
-                    codeUnitCount = ((payloadData.length + headerDataLen) * 8) / 7;
-                    uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
-                }
+                uData.payload = encode7bitAscii(uData.payloadStr, false);
+                uData.msgEncoding = UserData.ENCODING_7BIT_ASCII;
             } catch (CodingException ex) {
-                payloadData = encodeUtf16(uData.payloadStr);
-                codeUnitCount = uData.payloadStr.length();
+                uData.payload = encodeUtf16(uData.payloadStr);
                 uData.msgEncoding = UserData.ENCODING_UNICODE_16;
             }
+            uData.numFields = uData.payloadStr.length();
             uData.msgEncodingSet = true;
         }
-
-        int totalLength = payloadData.length + headerDataLen;
-        if (totalLength > SmsMessage.MAX_USER_DATA_BYTES) {
-            throw new CodingException("encoded user data too large (" + totalLength +
-                                      " > " + SmsMessage.MAX_USER_DATA_BYTES + " bytes)");
-        }
-
-        uData.numFields = codeUnitCount;
-        uData.payload = new byte[totalLength];
-        if (headerData != null) {
-            uData.payload[0] = (byte)headerData.length;
-            System.arraycopy(headerData, 0, uData.payload, 1, headerData.length);
-        }
-        System.arraycopy(payloadData, 0, uData.payload, headerDataLen, payloadData.length);
     }
 
     private static void encodeUserData(BearerData bData, BitwiseOutputStream outStream)
         throws BitwiseOutputStream.AccessException, CodingException
     {
+        /*
+         * TODO(cleanup): Do we really need to set userData.payload as
+         * a side effect of encoding?  If not, we could avoid data
+         * copies by passing outStream directly.
+         */
         encodeUserDataPayload(bData.userData);
+        if (bData.userData.payload.length > SmsMessage.MAX_USER_DATA_BYTES) {
+            throw new CodingException("encoded user data too large (" +
+                                      bData.userData.payload.length +
+                                      " > " + SmsMessage.MAX_USER_DATA_BYTES + " bytes)");
+        }
+
         /**
          * XXX/TODO: figure out what the right answer is WRT padding bits
          *
@@ -846,6 +890,9 @@
     private static String decodeUtf16(byte[] data, int offset, int numFields)
         throws CodingException
     {
+        // Start reading from the next 16-bit aligned boundry after offset.
+        int padding = offset % 2;
+        numFields -= (offset + padding) / 2;
         try {
             return new String(data, offset, numFields * 2, "utf-16be");
         } catch (java.io.UnsupportedEncodingException ex) {
@@ -889,11 +936,11 @@
     private static String decode7bitGsm(byte[] data, int offset, int numFields)
         throws CodingException
     {
-        int paddingBits = calcUdhSeptetPadding(offset);
-        numFields -= (((offset * 8) + paddingBits) / 7);
-        // TODO: It seems wrong that only Gsm7 bit encodings would
-        // take into account the header in numFields calculations.
-        // This should be verified.
+        // Start reading from the next 7-bit aligned boundry after offset.
+        int offsetBits = offset * 8;
+        int offsetSeptets = (offsetBits + 6) / 7;
+        numFields -= offsetSeptets;
+        int paddingBits = (offsetSeptets * 7) - offsetBits;
         String result = GsmAlphabet.gsm7BitPackedToString(data, offset, numFields, paddingBits);
         if (result == null) {
             throw new CodingException("7bit GSM decoding failed");
@@ -1106,7 +1153,7 @@
         if (paramBits >= EXPECTED_PARAM_SIZE) {
             paramBits -= EXPECTED_PARAM_SIZE;
             decodeSuccess = true;
-            bData.numberOfMessages = inStream.read(8);
+            bData.numberOfMessages = IccUtils.beBcdByteToInt((byte)inStream.read(8));
         }
         if ((! decodeSuccess) || (paramBits > 0)) {
             Log.d(LOG_TAG, "NUMBER_OF_MESSAGES decode " +
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index 6f89288..94d4344 100755
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -1032,11 +1032,13 @@
     /**
      * Small container class used to hold information relevant to
      * the carrier selection process. operatorNumeric can be ""
-     * if we are looking for automatic selection.
+     * if we are looking for automatic selection. operatorAlphaLong is the
+     * corresponding operator name.
      */
     private static class NetworkSelectMessage {
         public Message message;
         public String operatorNumeric;
+        public String operatorAlphaLong;
     }
 
     public void
@@ -1047,6 +1049,7 @@
         NetworkSelectMessage nsm = new NetworkSelectMessage();
         nsm.message = response;
         nsm.operatorNumeric = "";
+        nsm.operatorAlphaLong = "";
 
         // get the message
         Message msg = h.obtainMessage(EVENT_SET_NETWORK_AUTOMATIC_COMPLETE, nsm);
@@ -1064,6 +1067,7 @@
         NetworkSelectMessage nsm = new NetworkSelectMessage();
         nsm.message = response;
         nsm.operatorNumeric = network.operatorNumeric;
+        nsm.operatorAlphaLong = network.operatorAlphaLong;
 
         // get the message
         Message msg = h.obtainMessage(EVENT_SET_NETWORK_MANUAL_COMPLETE, nsm);
@@ -1499,6 +1503,7 @@
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
         SharedPreferences.Editor editor = sp.edit();
         editor.putString(NETWORK_SELECTION_KEY, nsm.operatorNumeric);
+        editor.putString(NETWORK_SELECTION_NAME_KEY, nsm.operatorAlphaLong);
 
         // commit and log the result.
         if (! editor.commit()) {
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
index db6e339..91c089e 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
@@ -294,12 +294,15 @@
     canDial() {
         boolean ret;
         int serviceState = phone.getServiceState().getState();
+        String disableCall = SystemProperties.get(
+                TelephonyProperties.PROPERTY_DISABLE_CALL, "false");
 
-        ret = (serviceState != ServiceState.STATE_POWER_OFF) &&
-                pendingMO == null
+        ret = (serviceState != ServiceState.STATE_POWER_OFF)
+                && pendingMO == null
                 && !ringingCall.isRinging()
+                && !disableCall.equals("true")
                 && (!foregroundCall.getState().isAlive()
-                || !backgroundCall.getState().isAlive());
+                    || !backgroundCall.getState().isAlive());
 
         return ret;
     }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index c33d4b6..8b3529f 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -52,6 +52,7 @@
 import com.android.internal.telephony.DataConnection;
 import com.android.internal.telephony.DataConnectionTracker;
 import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.RetryManager;
 import com.android.internal.telephony.TelephonyEventLog;
 import com.android.internal.telephony.DataConnection.FailCause;
 
@@ -85,7 +86,7 @@
     INetStatService netstat;
     // Indicates baseband will not auto-attach
     private boolean noAutoAttach = false;
-    long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+
     private boolean mReregisterOnReconnectFailure = false;
     private ContentResolver mResolver;
 
@@ -95,6 +96,11 @@
     private int mPdpResetCount = 0;
     private boolean mIsScreenOn = true;
 
+    private final RetryManager mRetryMgr = new RetryManager();
+
+    /** Delay between APN attempts */
+    protected static final int APN_DELAY_MILLIS = 5000;
+
     //useful for debugging
     boolean failNextConnect = false;
 
@@ -247,6 +253,15 @@
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
         dataEnabled[APN_DEFAULT_ID] = !sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false);
         noAutoAttach = !dataEnabled[APN_DEFAULT_ID];
+
+        if (!mRetryMgr.configure(SystemProperties.get("ro.gsm.data_retry_config"))) {
+            if (!mRetryMgr.configure(DEFAULT_DATA_RETRY_CONFIG)) {
+                // Should never happen, log an error and default to a simple linear sequence.
+                Log.e(LOG_TAG, "Could not configure using DEFAULT_DATA_RETRY_CONFIG="
+                        + DEFAULT_DATA_RETRY_CONFIG);
+                mRetryMgr.configure(20, 2000, 1000);
+            }
+        }
     }
 
     public void dispose() {
@@ -558,7 +573,7 @@
         } else {
             if (state == State.FAILED) {
                 cleanUpConnection(false, Phone.REASON_GPRS_ATTACHED);
-                nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+                mRetryMgr.resetRetryCount();
             }
             trySetupData(Phone.REASON_GPRS_ATTACHED);
         }
@@ -808,7 +823,7 @@
             cleanUpConnection(isConnected, Phone.REASON_APN_CHANGED);
             if (!isConnected) {
                 // reset reconnect timer
-                nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+                mRetryMgr.resetRetryCount();
                 mReregisterOnReconnectFailure = false;
                 trySetupData(Phone.REASON_APN_CHANGED);
             }
@@ -889,7 +904,7 @@
         phone.notifyDataConnection(reason);
         startNetStatPoll();
         // reset reconnect timer
-        nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+        mRetryMgr.resetRetryCount();
         mReregisterOnReconnectFailure = false;
     }
 
@@ -1175,20 +1190,21 @@
 
     private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) {
         if (state == State.FAILED) {
-            if (nextReconnectDelay > RECONNECT_DELAY_MAX_MILLIS) {
+            if (!mRetryMgr.isRetryNeeded()) {
                 if (mReregisterOnReconnectFailure) {
-                    // We have already tried to re-register to the network.
-                    // This might be a problem with the data network.
-                    nextReconnectDelay = RECONNECT_DELAY_MAX_MILLIS;
+                    // We've re-registerd once now just retry forever.
+                    mRetryMgr.retryForeverUsingLastTimeout();
                 } else {
-                    // Try to Re-register to the network.
+                    // Try to re-register to the network.
                     Log.d(LOG_TAG, "PDP activate failed, Reregistering to the network");
                     mReregisterOnReconnectFailure = true;
                     mGsmPhone.mSST.reRegisterNetwork(null);
-                    nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+                    mRetryMgr.resetRetryCount();
                     return;
                 }
             }
+
+            int nextReconnectDelay = mRetryMgr.getRetryTimer();
             Log.d(LOG_TAG, "PDP activate failed. Scheduling next attempt for "
                     + (nextReconnectDelay / 1000) + "s");
 
@@ -1202,8 +1218,7 @@
                     SystemClock.elapsedRealtime() + nextReconnectDelay,
                     mReconnectIntent);
 
-            // double it for next time
-            nextReconnectDelay *= 2;
+            mRetryMgr.increaseRetryCount();
 
             if (!shouldPostNotification(lastFailCauseCode)) {
                 Log.d(LOG_TAG,"NOT Posting GPRS Unavailable notification "
@@ -1276,7 +1291,7 @@
     protected void onRadioOffOrNotAvailable() {
         // Make sure our reconnect delay starts at the initial value
         // next time the radio comes on
-        nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+        mRetryMgr.resetRetryCount();
         mReregisterOnReconnectFailure = false;
 
         if (phone.getSimulatedRadioControl() != null) {
@@ -1361,8 +1376,7 @@
                 setState(State.SCANNING);
                 // Wait a bit before trying the next APN, so that
                 // we're not tying up the RIL command channel
-                sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason),
-                        RECONNECT_DELAY_INITIAL_MILLIS);
+                sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason), APN_DELAY_MILLIS);
             }
         }
     }
@@ -1407,7 +1421,7 @@
             }
         } else {
             // reset reconnect timer
-            nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+            mRetryMgr.resetRetryCount();
             mReregisterOnReconnectFailure = false;
             // in case data setup was attempted when we were on a voice call
             trySetupData(Phone.REASON_VOICE_CALL_ENDED);
@@ -1684,7 +1698,7 @@
                 } else {
                     if (state == State.FAILED) {
                         cleanUpConnection(false, Phone.REASON_PS_RESTRICT_ENABLED);
-                        nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+                        mRetryMgr.resetRetryCount();
                         mReregisterOnReconnectFailure = false;
                     }
                     trySetupData(Phone.REASON_PS_RESTRICT_ENABLED);
diff --git a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
index 365fee8..02af547 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
@@ -18,9 +18,11 @@
 
 import com.android.internal.telephony.GsmAlphabet;
 import com.android.internal.telephony.SmsHeader;
+import com.android.internal.telephony.cdma.SmsMessage;
 import com.android.internal.telephony.cdma.sms.BearerData;
 import com.android.internal.telephony.cdma.sms.UserData;
 import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
+import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
 import com.android.internal.util.BitwiseInputStream;
 import com.android.internal.util.BitwiseOutputStream;
 import com.android.internal.util.HexDump;
@@ -28,12 +30,12 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import android.util.Log;
+
 import java.util.Iterator;
 
 import java.lang.Integer;
 
-import android.util.Log;
-
 public class CdmaSmsTest extends AndroidTestCase {
     private final static String LOG_TAG = "CDMA";
 
@@ -151,6 +153,9 @@
         userData.payloadStr = "Test \n standard \r SMS";
         revBearerData = BearerData.decode(BearerData.encode(bearerData));
         assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+        userData.payloadStr = "";
+        revBearerData = BearerData.decode(BearerData.encode(bearerData));
+        assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
     }
 
     @SmallTest
@@ -172,6 +177,21 @@
         assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding);
         assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields);
         assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+        userData.payloadStr = "1234567";
+        revBearerData = BearerData.decode(BearerData.encode(bearerData));
+        assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+        userData.payloadStr = "";
+        revBearerData = BearerData.decode(BearerData.encode(bearerData));
+        assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+        userData.payloadStr = "12345678901234567890123456789012345678901234567890" +
+                "12345678901234567890123456789012345678901234567890" +
+                "12345678901234567890123456789012345678901234567890" +
+                "1234567890";
+        revBearerData = BearerData.decode(BearerData.encode(bearerData));
+        assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+        userData.payloadStr = "Test \u007f illegal \u0000 SMS chars";
+        revBearerData = BearerData.decode(BearerData.encode(bearerData));
+        assertEquals("Test   illegal   SMS chars", revBearerData.userData.payloadStr);
         userData.payloadStr = "More @ testing\nis great^|^~woohoo";
         revBearerData = BearerData.decode(BearerData.encode(bearerData));
         assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
@@ -220,6 +240,12 @@
         assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding);
         assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields);
         assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+        userData.payloadStr = "1234567";
+        revBearerData = BearerData.decode(BearerData.encode(bearerData));
+        assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+        userData.payloadStr = "";
+        revBearerData = BearerData.decode(BearerData.encode(bearerData));
+        assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
     }
 
     @SmallTest
@@ -784,4 +810,24 @@
         assertEquals(bd4.userData.payloadStr, "ABCDEFG");
     }
 
+    @SmallTest
+    public void testUserDataHeaderWithEightCharMsg() throws Exception {
+        BearerData bearerData = new BearerData();
+        bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER;
+        bearerData.messageId = 55;
+        SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
+        concatRef.refNumber = 0xEE;
+        concatRef.msgCount = 2;
+        concatRef.seqNumber = 2;
+        concatRef.isEightBits = true;
+        SmsHeader smsHeader = new SmsHeader();
+        smsHeader.concatRef = concatRef;
+        UserData userData = new UserData();
+        userData.payloadStr = "01234567";
+        userData.userDataHeader = smsHeader;
+        bearerData.userData = userData;
+        byte[] encodedSms = BearerData.encode(bearerData);
+        BearerData revBearerData = BearerData.decode(encodedSms);
+        assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+    }
 }
diff --git a/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java b/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java
index b4fb324..fdfafe1 100644
--- a/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java
+++ b/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java
@@ -47,6 +47,7 @@
         suite.addTestSuite(SimUtilsTest.class);
         suite.addTestSuite(SimPhoneBookTest.class);
         suite.addTestSuite(SimSmsTest.class);
+        suite.addTestSuite(TelephonyUtilsTest.class);
 
         return suite;
     }
diff --git a/tests/CoreTests/com/android/internal/telephony/TelephonyUtilsTest.java b/tests/CoreTests/com/android/internal/telephony/TelephonyUtilsTest.java
new file mode 100644
index 0000000..e4cf1e8
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/TelephonyUtilsTest.java
@@ -0,0 +1,196 @@
+/**
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import com.android.internal.telephony.RetryManager;
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class TelephonyUtilsTest extends TestCase {
+
+    /**
+     * After first creating the RetryManager
+     * isRetryNeeded should be false and the time 0
+     */
+    @SmallTest
+    public void testRetryManagerEmpty() throws Exception {
+        RetryManager rm = new RetryManager();
+
+        assertEquals(0, rm.getRetryCount());
+        assertFalse(rm.isRetryForever());
+        assertFalse(rm.isRetryNeeded());
+        assertEquals(0, rm.getRetryCount());
+        assertEquals(0, rm.getRetryTimer());
+
+        rm.increaseRetryCount();
+        assertFalse(rm.isRetryForever());
+        assertFalse(rm.isRetryNeeded());
+        assertEquals(0, rm.getRetryCount());
+        assertEquals(0, rm.getRetryTimer());
+
+        rm.setRetryCount(123);
+        assertFalse(rm.isRetryForever());
+        assertFalse(rm.isRetryNeeded());
+        assertEquals(0, rm.getRetryCount());
+        assertEquals(0, rm.getRetryTimer());
+
+        rm.retryForeverUsingLastTimeout();
+        assertTrue(rm.isRetryForever());
+        assertTrue(rm.isRetryNeeded());
+        assertEquals(0, rm.getRetryCount());
+        assertEquals(0, rm.getRetryTimer());
+
+        rm.setRetryCount(2);
+        assertFalse(rm.isRetryForever());
+        assertFalse(rm.isRetryNeeded());
+        assertEquals(0, rm.getRetryCount());
+        assertEquals(0, rm.getRetryTimer());
+    }
+
+    /**
+     * A simple test and that randomization is doing something.
+     */
+    @SmallTest
+    public void testRetryManagerSimplest() throws Exception {
+        RetryManager rm = new RetryManager();
+
+        assertTrue(rm.configure(1, 500, 10));
+        int loops = 10;
+        int count = 0;
+        for (int i = 0; i < loops; i++) {
+            assertTrue(rm.isRetryNeeded());
+            int time = rm.getRetryTimer();
+            assertTrue((time >= 500) && (time < 600));
+            if (time == 500) {
+                count++;
+            }
+        }
+        assertFalse(count == loops);
+        rm.increaseRetryCount();
+        assertFalse(rm.isRetryNeeded());
+        rm.setRetryCount(0);
+        assertTrue(rm.isRetryNeeded());
+    }
+
+    /**
+     * Test multiple values using simple configuration.
+     */
+    @SmallTest
+    public void testRetryManagerSimple() throws Exception {
+        RetryManager rm = new RetryManager();
+
+        assertTrue(rm.configure(3, 1000, 0));
+        assertTrue(rm.isRetryNeeded());
+        assertEquals(1000, rm.getRetryTimer());
+        assertEquals(rm.getRetryTimer(), 1000);
+        rm.increaseRetryCount();
+        assertTrue(rm.isRetryNeeded());
+        assertEquals(1000, rm.getRetryTimer());
+        rm.increaseRetryCount();
+        assertTrue(rm.isRetryNeeded());
+        assertEquals(1000, rm.getRetryTimer());
+        rm.increaseRetryCount();
+        assertFalse(rm.isRetryNeeded());
+        assertEquals(1000, rm.getRetryTimer());
+    }
+
+    /**
+     * Test string configuration, simplest
+     */
+    @SmallTest
+    public void testRetryManageSimpleString() throws Exception {
+        RetryManager rm = new RetryManager();
+
+        assertTrue(rm.configure("101"));
+        assertTrue(rm.isRetryNeeded());
+        assertEquals(101, rm.getRetryTimer());
+        rm.increaseRetryCount();
+        assertFalse(rm.isRetryNeeded());
+    }
+
+    /**
+     * Test string configuration using all options.
+     */
+    @SmallTest
+    public void testRetryManageString() throws Exception {
+        RetryManager rm = new RetryManager();
+        int time;
+
+        assertTrue(rm.configure("max_retries=4,"
+                  + "default_randomization=100,1000, 2000 :200 , 3000"));
+        assertTrue(rm.isRetryNeeded());
+        time = rm.getRetryTimer();
+        assertTrue((time >= 1000) && (time < 1100));
+
+        rm.increaseRetryCount();
+        assertTrue(rm.isRetryNeeded());
+        time = rm.getRetryTimer();
+        assertTrue((time >= 2000) && (time < 2200));
+
+        rm.increaseRetryCount();
+        assertTrue(rm.isRetryNeeded());
+        time = rm.getRetryTimer();
+        assertTrue((time >= 3000) && (time < 3100));
+
+        rm.increaseRetryCount();
+        assertTrue(rm.isRetryNeeded());
+        time = rm.getRetryTimer();
+        assertTrue((time >= 3000) && (time < 3100));
+
+        rm.increaseRetryCount();
+        assertFalse(rm.isRetryNeeded());
+    }
+
+    /**
+     * Test string configuration using all options.
+     */
+    @SmallTest
+    public void testRetryManageForever() throws Exception {
+        RetryManager rm = new RetryManager();
+        int time;
+
+        assertTrue(rm.configure("1000, 2000, 3000"));
+        assertTrue(rm.isRetryNeeded());
+        assertFalse(rm.isRetryForever());
+        assertEquals(0, rm.getRetryCount());
+        assertEquals(1000, rm.getRetryTimer());
+
+        rm.retryForeverUsingLastTimeout();
+        rm.increaseRetryCount();
+        rm.increaseRetryCount();
+        rm.increaseRetryCount();
+        assertTrue(rm.isRetryNeeded());
+        assertTrue(rm.isRetryForever());
+        assertEquals(3, rm.getRetryCount());
+        assertEquals(3000, rm.getRetryTimer());
+
+        rm.setRetryCount(1);
+        assertTrue(rm.isRetryNeeded());
+        assertFalse(rm.isRetryForever());
+        assertEquals(1, rm.getRetryCount());
+        assertEquals(2000, rm.getRetryTimer());
+
+        rm.retryForeverUsingLastTimeout();
+        assertTrue(rm.isRetryNeeded());
+        assertTrue(rm.isRetryForever());
+        rm.resetRetryCount();
+        assertTrue(rm.isRetryNeeded());
+        assertFalse(rm.isRetryForever());
+        assertEquals(0, rm.getRetryCount());
+        assertEquals(1000, rm.getRetryTimer());
+    }
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 69d3695..7e80370 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -630,7 +630,7 @@
         settings.setDatabaseEnabled(true);
         settings.setDatabasePath(getDir("databases",0).getAbsolutePath());
         settings.setDomStorageEnabled(true);
-        settings.setWorkersEnabled(true);
+        settings.setWorkersEnabled(false);
 
         webview.addJavascriptInterface(callbackProxy, "layoutTestController");
         webview.addJavascriptInterface(callbackProxy, "eventSender");
diff --git a/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java b/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java
index e9a43d7..1ba9d66a 100644
--- a/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java
+++ b/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java
@@ -16,7 +16,9 @@
 
 package android.content;
 
+import android.content.ContentValues;
 import android.database.Cursor;
+import android.database.MatrixCursor;
 import android.net.Uri;
 import android.os.Parcel;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -28,7 +30,9 @@
 import java.lang.reflect.InvocationTargetException;
 import java.util.HashMap;
 import java.util.Hashtable;
+import java.util.Set;
 import java.util.Map;
+import java.util.Map.Entry;
 
 @SmallTest
 public class ContentProviderOperationTest extends TestCase {
@@ -130,6 +134,46 @@
         assertEquals(sTestUri1.buildUpon().appendPath("19").toString(), result.uri.toString());
     }
 
+    public void testAssert() {
+        // Build an operation to assert values match provider
+        ContentProviderOperation op1 = ContentProviderOperation.newAssertQuery(sTestUri1)
+                .withValues(sTestValues1).build();
+
+        try {
+            // Assert that values match from cursor
+            ContentProviderResult result = op1.apply(new TestContentProvider() {
+                public Cursor query(Uri uri, String[] projection, String selection,
+                        String[] selectionArgs, String sortOrder) {
+                    // Return cursor over specific set of values
+                    return getCursor(sTestValues1);
+                }
+            }, null, 0);
+        } catch (OperationApplicationException e) {
+            fail("newAssert() failed");
+        }
+    }
+
+    /**
+     * Build a {@link Cursor} with a single row that contains all values
+     * provided through the given {@link ContentValues}.
+     */
+    private Cursor getCursor(ContentValues contentValues) {
+        final Set<Entry<String, Object>> valueSet = contentValues.valueSet();
+        final String[] keys = new String[valueSet.size()];
+        final Object[] values = new Object[valueSet.size()];
+
+        int i = 0;
+        for (Entry<String, Object> entry : valueSet) {
+            keys[i] = entry.getKey();
+            values[i] = entry.getValue();
+            i++;
+        }
+
+        final MatrixCursor cursor = new MatrixCursor(keys);
+        cursor.addRow(values);
+        return cursor;
+    }
+
     public void testValueBackRefs() {
         ContentValues values = new ContentValues();
         values.put("a", "in1");
@@ -167,11 +211,15 @@
 
         String[] selectionArgs = new String[]{"a", null, null, "b", null};
 
+        final ContentValues values = new ContentValues();
+        values.put("unused", "unused");
+
         ContentProviderOperation op1 = ContentProviderOperation.newUpdate(sTestUri1)
                 .withSelectionBackReference(1, 3)
                 .withSelectionBackReference(2, 1)
                 .withSelectionBackReference(4, 2)
                 .withSelection("unused", selectionArgs)
+                .withValues(values)
                 .build();
         String[] s2 = op1.resolveSelectionArgsBackReferences(
                 previousResults, previousResults.length);
@@ -212,7 +260,7 @@
             parcel.setDataPosition(0);
             op2 = ContentProviderOperation.CREATOR.createFromParcel(parcel);
 
-            assertEquals(1 /* ContentProviderOperation.TYPE_INSERT */, operationGetType(op2));
+            assertEquals(ContentProviderOperation.TYPE_INSERT, operationGetType(op2));
             assertEquals("content://goo/bar", operationGetUri(op2).toString());
             assertEquals(Integer.valueOf(42), operationGetExpectedCount(op2));
             assertEquals("selection", operationGetSelection(op2));
@@ -238,9 +286,8 @@
             op1.writeToParcel(parcel, 0);
             parcel.setDataPosition(0);
             op2 = ContentProviderOperation.CREATOR.createFromParcel(parcel);
-            assertEquals(2 /* ContentProviderOperation.TYPE_UPDATE */, operationGetType(op2));
+            assertEquals(ContentProviderOperation.TYPE_UPDATE, operationGetType(op2));
             assertEquals("content://goo/bar", operationGetUri(op2).toString());
-            assertNull(operationGetEntity(op2));
             assertNull(operationGetExpectedCount(op2));
             assertNull(operationGetSelection(op2));
             assertNull(operationGetSelectionArgs(op2));
@@ -261,9 +308,8 @@
             op1.writeToParcel(parcel, 0);
             parcel.setDataPosition(0);
             op2 = ContentProviderOperation.CREATOR.createFromParcel(parcel);
-            assertEquals(3 /* ContentProviderOperation.TYPE_DELETE */, operationGetType(op2));
+            assertEquals(ContentProviderOperation.TYPE_DELETE, operationGetType(op2));
             assertEquals("content://goo/bar", operationGetUri(op2).toString());
-            assertNull(operationGetEntity(op2));
             assertNull(operationGetExpectedCount(op2));
             assertNull(operationGetSelection(op2));
             assertNull(operationGetSelectionArgs(op2));
@@ -329,15 +375,6 @@
         field.set(builder, values);
     }
 
-    private void builderSetEntity(
-            ContentProviderOperation.Builder builder, Entity entity)
-            throws NoSuchFieldException, IllegalAccessException {
-        Field field;
-        field = CLASS_BUILDER.getDeclaredField("mEntity");
-        field.setAccessible(true);
-        field.set(builder, entity);
-    }
-
     private void builderSetExpectedCount(
             ContentProviderOperation.Builder builder, Integer expectedCount)
             throws NoSuchFieldException, IllegalAccessException {
@@ -382,13 +419,6 @@
         return (ContentValues) field.get(operation);
     }
 
-    private Entity operationGetEntity(ContentProviderOperation operation)
-            throws NoSuchFieldException, IllegalAccessException {
-        final Field field = CLASS_OPERATION.getDeclaredField("mEntity");
-        field.setAccessible(true);
-        return (Entity) field.get(operation);
-    }
-
     private Integer operationGetExpectedCount(ContentProviderOperation operation)
             throws NoSuchFieldException, IllegalAccessException {
         final Field field = CLASS_OPERATION.getDeclaredField("mExpectedCount");
diff --git a/tests/backup/test_backup.sh b/tests/backup/test_backup.sh
index f50d03f..10b809d 100755
--- a/tests/backup/test_backup.sh
+++ b/tests/backup/test_backup.sh
@@ -14,39 +14,32 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# uncomment for debugging
+#export DRY_RUN="echo"
+source test_backup_common.sh
 
-ADB_OPTS="$@"
+# wipe prior backup data for packages
+b_pkgs=$(a shell dumpsys backup | \
+         ruby -ne 'print($1+" ") if $_ =~ /^\s*ApplicationInfo\S+ (.+?)\}/')
 
-#FIXME: what was this for?
-#adb kill-server
-
-b_pkgs=$(adb $ADB_OPTS shell dumpsys backup | \
-         ruby -ne 'print($1+" ") if $_ =~ /^\s*ApplicationInfo\{\S+ (.+?)\}/')
-
-# wipe prior backup data for packages, including the metadata package @pm@
-for pkg in $b_pkgs '@pm@'; do
-    adb $ADB_OPTS shell bmgr wipe "$pkg"
+for pkg in $b_pkgs; do
+    a shell bmgr wipe "$pkg"
 done
 
-# who knows?
 echo 'Waiting 5 seconds for things to settle...'
 sleep 5
 
 # run adb as root so we can poke at com.android.backuptest's data
-root_status=$(adb $ADB_OPTS root)
-if [ "x$root_status" != "xadbd is already running as root" ]; then
-    sleep 2
-    adb $ADB_OPTS 'wait-for-device'
-fi
+adb_root
 
 # show commands as we go
 set -x
 
 # set the transport
-adb $ADB_OPTS shell bmgr transport com.google.android.backup/.BackupTransportService
+a shell bmgr transport com.google.android.backup/.BackupTransportService
 
 # load up the three files
-adb $ADB_OPTS shell \
+a shell \
    "rm /data/data/com.android.backuptest/files/file.txt ; \
     rm /data/data/com.android.backuptest/files/another_file.txt ; \
     rm /data/data/com.android.backuptest/files/empty.txt ; \
@@ -63,8 +56,8 @@
 #    echo -n 3 > /data/data/com.android.backuptest/files/3.txt ; \
 
 # say that the data has changed
-adb $ADB_OPTS shell bmgr backup com.android.backuptest
+a shell bmgr backup com.android.backuptest
 
 # run the backup
-adb $ADB_OPTS shell bmgr run
+a shell bmgr run
 
diff --git a/tests/backup/test_backup_common.sh b/tests/backup/test_backup_common.sh
new file mode 100755
index 0000000..61ec833
--- /dev/null
+++ b/tests/backup/test_backup_common.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+export ADB_OPTS="$@"
+
+# run adb with options
+function a { $DRY_RUN adb $ADB_OPTS "$@"; }
+
+# restart adb as root and wait for it to come back again
+function adb_root
+{
+    root_status=$(a root)
+    if [ "$root_status" != "adbd is already running as root" ]; then
+        echo -n "Restarting adb as root..."
+        sleep 2
+        a 'wait-for-device'
+        echo done.
+    fi
+}
+
diff --git a/tests/backup/test_restore.sh b/tests/backup/test_restore.sh
index 44b3a28..4506c16 100755
--- a/tests/backup/test_restore.sh
+++ b/tests/backup/test_restore.sh
@@ -14,76 +14,96 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# uncomment for debugging
+#export DRY_RUN="echo"
+source test_backup_common.sh
 
-ADB_OPTS="$@"
+BUGREPORT_DIR="$HOME/backup/bugreports"
 
 function check_file
 {
-    data=$(adb $ADB_OPTS shell cat /data/data/com.android.backuptest/$1)
+    data=$(a shell cat /data/data/com.android.backuptest/$1)
     if [ "$data" = "$2" ] ; then
         echo "$1 has correct value [$2]"
+        return 0
     else
         echo $1 is INCORRECT
         echo "   value:    [$data]"
         echo "   expected: [$2]"
+        return 1
+    fi
+}
+
+function check_exists
+{
+    # return 0 if file exists, 1 otherwise
+    data=$(a shell "ls $@ 2> /dev/null >/dev/null && echo -n exists")
+    if [ "$data" = "exists" ]; then
+        return 0
+    else
+        return 1
     fi
 }
 
 # run adb as root so we can poke at com.android.backuptest's data
-root_status=$(adb $ADB_OPTS root)
-if [ "x$root_status" != "xadbd is already running as root" ]; then
-    echo -n "Restarting adb as root..."
-    sleep 2
-    adb $ADB_OPTS 'wait-for-device'
-    echo done.
-fi
+adb_root
 
 # delete the old data
 echo --- Previous files
-adb $ADB_OPTS shell "ls -l /data/data/com.android.backuptest/files"
-adb $ADB_OPTS shell "rm /data/data/com.android.backuptest/files/*"
+a shell "ls -l /data/data/com.android.backuptest/files"
+a shell "rm /data/data/com.android.backuptest/files/*"
 echo --- Previous shared_prefs
-adb $ADB_OPTS shell "ls -l /data/data/com.android.backuptest/shared_prefs"
-adb $ADB_OPTS shell "rm /data/data/com.android.backuptest/shared_prefs/*"
+a shell "ls -l /data/data/com.android.backuptest/shared_prefs"
+a shell "rm /data/data/com.android.backuptest/shared_prefs/*"
 echo --- Erased files and shared_prefs
-adb $ADB_OPTS shell "ls -l /data/data/com.android.backuptest/files"
-adb $ADB_OPTS shell "ls -l /data/data/com.android.backuptest/shared_prefs"
+a shell "ls -l /data/data/com.android.backuptest/files"
+a shell "ls -l /data/data/com.android.backuptest/shared_prefs"
 echo ---
 
 echo
 echo
-echo
 
 # FIXME: there's probably a smarter way to do this
 # FIXME: if we can get the android ID, that's probably the safest thing to do
 # pick the most recent set and restore from it
-restore_set=$(adb $ADB_OPTS shell bmgr list sets | head -n1 | awk '{print $1}')
+restore_set=$(a shell bmgr list sets | head -n1 | awk '{print $1}')
 
 # run the restore
-printf "Restoring from set %d (hex: 0x%x)\n" $restore_set $restore_set
-adb $ADB_OPTS shell bmgr restore $restore_set
+echo "Restoring from set [$restore_set]"
+a shell bmgr restore "$restore_set"
 
 echo
 echo
-echo
 
 # check the results
-check_file files/file.txt "first file"
-check_file files/another_file.txt "asdf"
-#check_file files/3.txt "3"
-check_file files/empty.txt ""
-check_file shared_prefs/raw.xml '<map><int name="pref" value="1" /></map>'
+export need_bug=0
+
+# make sure files have the expected contents
+check_file files/file.txt "first file" || need_bug=1
+check_file files/another_file.txt "asdf" || need_bug=1
+#check_file files/3.txt "3" || need_bug=1
+check_file files/empty.txt "" || need_bug=1
+check_file shared_prefs/raw.xml '<map><int name="pref" value="1" /></map>' || need_bug=1
+
+# make sure that missing files weren't somehow created
+check_exists files/file_doesnt_exist.txt && need_bug=1
+check_exists files/no_files_here.txt && need_bug=1
+
+if [ \( "$need_bug" -ne 0 \) -a -d "$BUGREPORT_DIR" ]; then
+    dev_id=$(a get-serialno)
+    filename="${dev_id}_`date +%s`"
+    echo "Grabbing bugreport; filename is $filename"
+    a bugreport > "$BUGREPORT_DIR/$filename.txt"
+fi
 
 echo
-echo
-echo
 echo --- Restored files
-adb $ADB_OPTS shell "ls -l /data/data/com.android.backuptest/files"
+a shell "ls -l /data/data/com.android.backuptest/files"
 echo --- Restored shared_prefs
-adb $ADB_OPTS shell "ls -l /data/data/com.android.backuptest/shared_prefs"
+a shell "ls -l /data/data/com.android.backuptest/shared_prefs"
 echo ---
 echo
 
 echo "Last 3 timestamps in 3.txt:"
-adb $ADB_OPTS shell cat /data/data/com.android.backuptest/files/3.txt | tail -n 3
+a shell cat /data/data/com.android.backuptest/files/3.txt | tail -n 3
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index fd77d51..8e7d48f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -990,6 +990,10 @@
             // pass for now.
         }
 
+        public void setWallpaperPosition(IBinder window, float x, float y) {
+            // pass for now.
+        }
+        
         public IBinder asBinder() {
             // pass for now.
             return null;