Merge "All SuggestionSpans are removed when the window loses focus."
diff --git a/Android.mk b/Android.mk
index 898d7e2..2329be2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -422,6 +422,8 @@
 		            resources/samples/TicTacToeLib "TicTacToeLib" \
 		-samplecode $(sample_dir)/TicTacToeMain \
 		            resources/samples/TicTacToeMain "TicTacToeMain" \
+		-samplecode $(sample_dir)/USB \
+		            resources/samples/USB "USB" \
 		-samplecode $(sample_dir)/WeatherListWidget \
 		            resources/samples/WeatherListWidget "Weather List Widget" \
 		-samplecode $(sample_dir)/Wiktionary \
@@ -435,7 +437,7 @@
 
 ## SDK version identifiers used in the published docs
   # major[.minor] version for current SDK. (full releases only)
-framework_docs_SDK_VERSION:=3.0
+framework_docs_SDK_VERSION:=3.1
   # release version (ie "Release x")  (full releases only)
 framework_docs_SDK_REL_ID:=1
 
diff --git a/api/current.txt b/api/current.txt
index a98ffae..950c130 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -21025,6 +21025,7 @@
 
   public static abstract interface TextureView.SurfaceTextureListener {
     method public abstract void onSurfaceTextureAvailable(android.graphics.SurfaceTexture);
+    method public abstract void onSurfaceTextureSizeChanged(android.graphics.SurfaceTexture, int, int);
   }
 
   public class TouchDelegate {
@@ -21724,6 +21725,7 @@
     method public void setOnHierarchyChangeListener(android.view.ViewGroup.OnHierarchyChangeListener);
     method public void setPersistentDrawingCache(int);
     method protected void setStaticTransformationsEnabled(boolean);
+    method public boolean shouldDelayChildPressedState();
     method public boolean showContextMenuForChild(android.view.View);
     method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback);
     method public void startLayoutAnimation();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4dfba91..79552bf 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -70,7 +70,7 @@
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewManager;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
@@ -728,7 +728,7 @@
             long dalvikFree = runtime.freeMemory() / 1024;
             long dalvikAllocated = dalvikMax - dalvikFree;
             long viewInstanceCount = ViewDebug.getViewInstanceCount();
-            long viewRootInstanceCount = ViewDebug.getViewRootInstanceCount();
+            long viewRootInstanceCount = ViewDebug.getViewAncestorInstanceCount();
             long appContextInstanceCount = Debug.countInstancesOfClass(ContextImpl.class);
             long activityInstanceCount = Debug.countInstancesOfClass(Activity.class);
             int globalAssetCount = AssetManager.getGlobalAssetCount();
@@ -843,7 +843,7 @@
 
             pw.println(" ");
             pw.println(" Objects");
-            printRow(pw, TWO_COUNT_COLUMNS, "Views:", viewInstanceCount, "ViewRoots:",
+            printRow(pw, TWO_COUNT_COLUMNS, "Views:", viewInstanceCount, "ViewAncestors:",
                     viewRootInstanceCount);
 
             printRow(pw, TWO_COUNT_COLUMNS, "AppContexts:", appContextInstanceCount,
@@ -3918,7 +3918,7 @@
         sThreadLocal.set(this);
         mSystemThread = system;
         if (!system) {
-            ViewRoot.addFirstDrawHandler(new Runnable() {
+            ViewAncestor.addFirstDrawHandler(new Runnable() {
                 public void run() {
                     ensureJitEnabled();
                 }
@@ -3948,7 +3948,7 @@
             }
         }
         
-        ViewRoot.addConfigCallback(new ComponentCallbacks() {
+        ViewAncestor.addConfigCallback(new ComponentCallbacks() {
             public void onConfigurationChanged(Configuration newConfig) {
                 synchronized (mPackages) {
                     // We need to apply this change to the resources
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 087753b..82186dd 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -931,7 +931,7 @@
 
         // associate search with owner activity
         final ComponentName appName = getAssociatedActivity();
-        if (appName != null) {
+        if (appName != null && searchManager.getSearchableInfo(appName) != null) {
             searchManager.startSearch(null, false, appName, null, false);
             dismiss();
             return true;
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 13a8b78..113c610 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -38,7 +38,7 @@
 import android.os.ServiceManager;
 import android.util.DisplayMetrics;
 import android.util.Log;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
 
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -632,7 +632,7 @@
     public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
         try {
             //Log.v(TAG, "Sending new wallpaper offsets from app...");
-            ViewRoot.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+            ViewAncestor.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
                     windowToken, xOffset, yOffset, mWallpaperXStep, mWallpaperYStep);
             //Log.v(TAG, "...app returning after sending offsets!");
         } catch (RemoteException e) {
@@ -670,7 +670,7 @@
             int x, int y, int z, Bundle extras) {
         try {
             //Log.v(TAG, "Sending new wallpaper offsets from app...");
-            ViewRoot.getWindowSession(mContext.getMainLooper()).sendWallpaperCommand(
+            ViewAncestor.getWindowSession(mContext.getMainLooper()).sendWallpaperCommand(
                     windowToken, action, x, y, z, extras, false);
             //Log.v(TAG, "...app returning after sending offsets!");
         } catch (RemoteException e) {
@@ -690,7 +690,7 @@
      */
     public void clearWallpaperOffsets(IBinder windowToken) {
         try {
-            ViewRoot.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+            ViewAncestor.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
                     windowToken, -1, -1, -1, -1);
         } catch (RemoteException e) {
             // Ignore.
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 49db72b..6d955e7 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1179,6 +1179,8 @@
         private static final String KEY_MAX_EXPOSURE_COMPENSATION = "max-exposure-compensation";
         private static final String KEY_MIN_EXPOSURE_COMPENSATION = "min-exposure-compensation";
         private static final String KEY_EXPOSURE_COMPENSATION_STEP = "exposure-compensation-step";
+        private static final String KEY_AUTO_EXPOSURE_LOCK = "auto-exposure-lock";
+        private static final String KEY_AUTO_EXPOSURE_LOCK_SUPPORTED = "auto-exposure-lock-supported";
         private static final String KEY_METERING_AREAS = "metering-areas";
         private static final String KEY_MAX_NUM_METERING_AREAS = "max-num-metering-areas";
         private static final String KEY_ZOOM = "zoom";
@@ -1195,6 +1197,7 @@
         private static final String SUPPORTED_VALUES_SUFFIX = "-values";
 
         private static final String TRUE = "true";
+        private static final String FALSE = "false";
 
         // Values for white balance settings.
         public static final String WHITE_BALANCE_AUTO = "auto";
@@ -1565,7 +1568,9 @@
         }
 
         /**
-         * Sets the dimensions for preview pictures.
+         * Sets the dimensions for preview pictures. If the preview has already
+         * started, applications should stop the preview first before changing
+         * preview size.
          *
          * The sides of width and height are based on camera orientation. That
          * is, the preview size is the size before it is rotated by display
@@ -2463,6 +2468,80 @@
         }
 
         /**
+         * Sets the auto-exposure lock state. Applications should check
+         * {@link #isAutoExposureLockSupported} before using this method.
+         *
+         * If set to true, the camera auto-exposure routine will pause until the
+         * lock is set to false. Exposure compensation settings changes will
+         * still take effect while auto-exposure is locked. Stopping preview
+         * with {@link #stopPreview()}, or triggering still image capture with
+         * {@link #takePicture(Camera.ShutterCallback, Camera.PictureCallback,
+         * Camera.PictureCallback)}, will automatically set the lock to
+         * false. However, the lock can be re-enabled before preview is
+         * re-started to keep the same AE parameters. Exposure compensation, in
+         * conjunction with re-enabling the AE lock after each still capture,
+         * can be used to capture an exposure-bracketed burst of images, for
+         * example. Auto-exposure state, including the lock state, will not be
+         * maintained after camera {@link #release()} is called.  Locking
+         * auto-exposure after {@link #open()} but before the first call to
+         * {@link #startPreview()} will not allow the auto-exposure routine to
+         * run at all, and may result in severely over- or under-exposed images.
+         *
+         * The driver may also independently lock auto-exposure after auto-focus
+         * completes. If this is undesirable, be sure to always set the
+         * auto-exposure lock to false after the
+         * {@link AutoFocusCallback#onAutoFocus(boolean, Camera)} callback is
+         * received. The {@link #getAutoExposureLock()} method can be used after
+         * the callback to determine if the camera has locked auto-exposure
+         * independently.
+         *
+         * @param toggle new state of the auto-exposure lock. True means that
+         *        auto-exposure is locked, false means that the auto-exposure
+         *        routine is free to run normally.
+         *
+         * @hide
+         */
+        public void setAutoExposureLock(boolean toggle) {
+            set(KEY_AUTO_EXPOSURE_LOCK, toggle ? TRUE : FALSE);
+        }
+
+        /**
+         * Gets the state of the auto-exposure lock. Applications should check
+         * {@link #isAutoExposureLockSupported} before using this method. See
+         * {@link #setAutoExposureLock} for details about the lock.
+         *
+         * @return State of the auto-exposure lock. Returns true if
+         *         auto-exposure is currently locked, and false otherwise. The
+         *         auto-exposure lock may be independently enabled by the camera
+         *         subsystem when auto-focus has completed. This method can be
+         *         used after the {@link AutoFocusCallback#onAutoFocus(boolean,
+         *         Camera)} callback to determine if the camera has locked AE.
+         *
+         * @see #setAutoExposureLock(boolean)
+         *
+         * @hide
+         */
+        public boolean getAutoExposureLock() {
+            String str = get(KEY_AUTO_EXPOSURE_LOCK);
+            return TRUE.equals(str);
+        }
+
+        /**
+         * Returns true if auto-exposure locking is supported. Applications
+         * should call this before trying to lock auto-exposure. See
+         * {@link #setAutoExposureLock} for details about the lock.
+         *
+         * @return true if auto-exposure lock is supported.
+         * @see #setAutoExposureLock(boolean)
+         *
+         * @hide
+         */
+        public boolean isAutoExposureLockSupported() {
+            String str = get(KEY_AUTO_EXPOSURE_LOCK_SUPPORTED);
+            return TRUE.equals(str);
+        }
+
+        /**
          * Gets current zoom value. This also works when smooth zoom is in
          * progress. Applications should check {@link #isZoomSupported} before
          * using this method.
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 91f0098..b111b84 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -204,6 +204,12 @@
      * values[0]: Ambient light level in SI lux units
      * </ul>
      * 
+     * <h4>{@link android.hardware.Sensor#TYPE_PRESSURE Sensor.TYPE_PRESSURE}:</h4>
+     * <ul>
+     * <p>
+     * values[0]: Atmospheric pressure in hPa (millibar)
+     * </ul>
+     *
      * <h4>{@link android.hardware.Sensor#TYPE_PROXIMITY Sensor.TYPE_PROXIMITY}:
      * </h4>
      * 
@@ -247,6 +253,23 @@
      *  <p>Elements of the rotation vector are unitless.
      *  The x,y, and z axis are defined in the same way as the acceleration
      *  sensor.</p>
+     *  The reference coordinate system is defined as a direct orthonormal basis,
+     *  where:
+     * </p>
+     *
+     * <ul>
+     * <li>X is defined as the vector product <b>Y.Z</b> (It is tangential to
+     * the ground at the device's current location and roughly points East).</li>
+     * <li>Y is tangential to the ground at the device's current location and
+     * points towards the magnetic North Pole.</li>
+     * <li>Z points towards the sky and is perpendicular to the ground.</li>
+     * </ul>
+     *
+     * <p>
+     * <center><img src="../../../images/axis_globe.png"
+     * alt="World coordinate-system diagram." border="0" /></center>
+     * </p>
+     *
      * <ul>
      * <p>
      * values[0]: x*sin(&#952/2)
diff --git a/core/java/android/net/DhcpInfoInternal.java b/core/java/android/net/DhcpInfoInternal.java
index 7396669..860da0a 100644
--- a/core/java/android/net/DhcpInfoInternal.java
+++ b/core/java/android/net/DhcpInfoInternal.java
@@ -22,6 +22,8 @@
 import java.net.InetAddress;
 import java.net.Inet4Address;
 import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collection;
 
 /**
  * A simple object for retrieving the results of a DHCP request.
@@ -31,7 +33,6 @@
 public class DhcpInfoInternal {
     private final static String TAG = "DhcpInfoInternal";
     public String ipAddress;
-    public String gateway;
     public int prefixLength;
 
     public String dns1;
@@ -40,7 +41,14 @@
     public String serverAddress;
     public int leaseDuration;
 
+    private Collection<RouteInfo> routes;
+
     public DhcpInfoInternal() {
+        routes = new ArrayList<RouteInfo>();
+    }
+
+    public void addRoute(RouteInfo routeInfo) {
+        routes.add(routeInfo);
     }
 
     private int convertToInt(String addr) {
@@ -58,7 +66,12 @@
     public DhcpInfo makeDhcpInfo() {
         DhcpInfo info = new DhcpInfo();
         info.ipAddress = convertToInt(ipAddress);
-        info.gateway = convertToInt(gateway);
+        for (RouteInfo route : routes) {
+            if (route.isDefaultRoute()) {
+                info.gateway = convertToInt(route.getGateway().getHostAddress());
+                break;
+            }
+        }
         try {
             InetAddress inetAddress = NetworkUtils.numericToInetAddress(ipAddress);
             info.netmask = NetworkUtils.prefixLengthToNetmaskInt(prefixLength);
@@ -81,8 +94,8 @@
     public LinkProperties makeLinkProperties() {
         LinkProperties p = new LinkProperties();
         p.addLinkAddress(makeLinkAddress());
-        if (TextUtils.isEmpty(gateway) == false) {
-            p.addGateway(NetworkUtils.numericToInetAddress(gateway));
+        for (RouteInfo route : routes) {
+            p.addRoute(route);
         }
         if (TextUtils.isEmpty(dns1) == false) {
             p.addDns(NetworkUtils.numericToInetAddress(dns1));
@@ -98,8 +111,10 @@
     }
 
     public String toString() {
+        String routeString = "";
+        for (RouteInfo route : routes) routeString += route.toString() + " | ";
         return "addr: " + ipAddress + "/" + prefixLength +
-                " gateway: " + gateway +
+                " routes: " + routeString +
                 " dns: " + dns1 + "," + dns2 +
                 " dhcpServer: " + serverAddress +
                 " leaseDuration: " + leaseDuration;
diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java
new file mode 100644
index 0000000..eaf087f
--- /dev/null
+++ b/core/java/android/net/DhcpStateMachine.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2011 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.net;
+
+import com.android.internal.util.Protocol;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.DhcpInfoInternal;
+import android.net.NetworkUtils;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.util.Log;
+
+/**
+ * StateMachine that interacts with the native DHCP client and can talk to
+ * a controller that also needs to be a StateMachine
+ *
+ * The Dhcp state machine provides the following features:
+ * - Wakeup and renewal using the native DHCP client  (which will not renew
+ *   on its own when the device is in suspend state and this can lead to device
+ *   holding IP address beyond expiry)
+ * - A notification right before DHCP request or renewal is started. This
+ *   can be used for any additional setup before DHCP. For example, wifi sets
+ *   BT-Wifi coex settings right before DHCP is initiated
+ *
+ * @hide
+ */
+public class DhcpStateMachine extends StateMachine {
+
+    private static final String TAG = "DhcpStateMachine";
+    private static final boolean DBG = false;
+
+
+    /* A StateMachine that controls the DhcpStateMachine */
+    private StateMachine mController;
+
+    private Context mContext;
+    private BroadcastReceiver mBroadcastReceiver;
+    private AlarmManager mAlarmManager;
+    private PendingIntent mDhcpRenewalIntent;
+    private PowerManager.WakeLock mDhcpRenewWakeLock;
+    private static final String WAKELOCK_TAG = "DHCP";
+
+    private static final int DHCP_RENEW = 0;
+    private static final String ACTION_DHCP_RENEW = "android.net.wifi.DHCP_RENEW";
+
+    private enum DhcpAction {
+        START,
+        RENEW
+    };
+
+    private String mInterfaceName;
+    private boolean mRegisteredForPreDhcpNotification = false;
+
+    private static final int BASE = Protocol.BASE_DHCP;
+
+    /* Commands from controller to start/stop DHCP */
+    public static final int CMD_START_DHCP                  = BASE + 1;
+    public static final int CMD_STOP_DHCP                   = BASE + 2;
+    public static final int CMD_RENEW_DHCP                  = BASE + 3;
+
+    /* Notification from DHCP state machine prior to DHCP discovery/renewal */
+    public static final int CMD_PRE_DHCP_ACTION             = BASE + 4;
+    /* Notification from DHCP state machine post DHCP discovery/renewal. Indicates
+     * success/failure */
+    public static final int CMD_POST_DHCP_ACTION            = BASE + 5;
+
+    /* Command from controller to indicate DHCP discovery/renewal can continue
+     * after pre DHCP action is complete */
+    public static final int CMD_PRE_DHCP_ACTION_COMPLETE    = BASE + 6;
+
+    /* Message.arg1 arguments to CMD_POST_DHCP notification */
+    public static final int DHCP_SUCCESS = 1;
+    public static final int DHCP_FAILURE = 2;
+
+    private State mDefaultState = new DefaultState();
+    private State mStoppedState = new StoppedState();
+    private State mWaitBeforeStartState = new WaitBeforeStartState();
+    private State mRunningState = new RunningState();
+    private State mWaitBeforeRenewalState = new WaitBeforeRenewalState();
+
+    private DhcpStateMachine(Context context, StateMachine controller, String intf) {
+        super(TAG);
+
+        mContext = context;
+        mController = controller;
+        mInterfaceName = intf;
+
+        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+        Intent dhcpRenewalIntent = new Intent(ACTION_DHCP_RENEW, null);
+        mDhcpRenewalIntent = PendingIntent.getBroadcast(mContext, DHCP_RENEW, dhcpRenewalIntent, 0);
+
+        PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+        mDhcpRenewWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
+
+        mBroadcastReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                //DHCP renew
+                if (DBG) Log.d(TAG, "Sending a DHCP renewal " + this);
+                //acquire a 40s wakelock to finish DHCP renewal
+                mDhcpRenewWakeLock.acquire(40000);
+                sendMessage(CMD_RENEW_DHCP);
+            }
+        };
+        mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(ACTION_DHCP_RENEW));
+
+        addState(mDefaultState);
+            addState(mStoppedState, mDefaultState);
+            addState(mWaitBeforeStartState, mDefaultState);
+            addState(mRunningState, mDefaultState);
+            addState(mWaitBeforeRenewalState, mDefaultState);
+
+        setInitialState(mStoppedState);
+    }
+
+    public static DhcpStateMachine makeDhcpStateMachine(Context context, StateMachine controller,
+            String intf) {
+        DhcpStateMachine dsm = new DhcpStateMachine(context, controller, intf);
+        dsm.start();
+        return dsm;
+    }
+
+    /**
+     * This sends a notification right before DHCP request/renewal so that the
+     * controller can do certain actions before DHCP packets are sent out.
+     * When the controller is ready, it sends a CMD_PRE_DHCP_ACTION_COMPLETE message
+     * to indicate DHCP can continue
+     *
+     * This is used by Wifi at this time for the purpose of doing BT-Wifi coex
+     * handling during Dhcp
+     */
+    public void registerForPreDhcpNotification() {
+        mRegisteredForPreDhcpNotification = true;
+    }
+
+    class DefaultState extends State {
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch (message.what) {
+                case CMD_RENEW_DHCP:
+                    Log.e(TAG, "Error! Failed to handle a DHCP renewal on " + mInterfaceName);
+                    break;
+                case SM_QUIT_CMD:
+                    mContext.unregisterReceiver(mBroadcastReceiver);
+                    //let parent kill the state machine
+                    return NOT_HANDLED;
+                default:
+                    Log.e(TAG, "Error! unhandled message  " + message);
+                    break;
+            }
+            return HANDLED;
+        }
+    }
+
+
+    class StoppedState extends State {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            boolean retValue = HANDLED;
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch (message.what) {
+                case CMD_START_DHCP:
+                    if (mRegisteredForPreDhcpNotification) {
+                        /* Notify controller before starting DHCP */
+                        mController.sendMessage(CMD_PRE_DHCP_ACTION);
+                        transitionTo(mWaitBeforeStartState);
+                    } else {
+                        if (runDhcp(DhcpAction.START)) {
+                            transitionTo(mRunningState);
+                        }
+                    }
+                    break;
+                case CMD_STOP_DHCP:
+                    //ignore
+                    break;
+                default:
+                    retValue = NOT_HANDLED;
+                    break;
+            }
+            return retValue;
+        }
+    }
+
+    class WaitBeforeStartState extends State {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            boolean retValue = HANDLED;
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch (message.what) {
+                case CMD_PRE_DHCP_ACTION_COMPLETE:
+                    if (runDhcp(DhcpAction.START)) {
+                        transitionTo(mRunningState);
+                    } else {
+                        transitionTo(mStoppedState);
+                    }
+                    break;
+                case CMD_STOP_DHCP:
+                    transitionTo(mStoppedState);
+                    break;
+                case CMD_START_DHCP:
+                    //ignore
+                    break;
+                default:
+                    retValue = NOT_HANDLED;
+                    break;
+            }
+            return retValue;
+        }
+    }
+
+    class RunningState extends State {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            boolean retValue = HANDLED;
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch (message.what) {
+                case CMD_STOP_DHCP:
+                    mAlarmManager.cancel(mDhcpRenewalIntent);
+                    if (!NetworkUtils.stopDhcp(mInterfaceName)) {
+                        Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName);
+                    }
+                    transitionTo(mStoppedState);
+                    break;
+                case CMD_RENEW_DHCP:
+                    if (mRegisteredForPreDhcpNotification) {
+                        /* Notify controller before starting DHCP */
+                        mController.sendMessage(CMD_PRE_DHCP_ACTION);
+                        transitionTo(mWaitBeforeRenewalState);
+                    } else {
+                        if (!runDhcp(DhcpAction.RENEW)) {
+                            transitionTo(mStoppedState);
+                        }
+                    }
+                    break;
+                case CMD_START_DHCP:
+                    //ignore
+                    break;
+                default:
+                    retValue = NOT_HANDLED;
+            }
+            return retValue;
+        }
+    }
+
+    class WaitBeforeRenewalState extends State {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            boolean retValue = HANDLED;
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch (message.what) {
+                case CMD_STOP_DHCP:
+                    mAlarmManager.cancel(mDhcpRenewalIntent);
+                    if (!NetworkUtils.stopDhcp(mInterfaceName)) {
+                        Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName);
+                    }
+                    transitionTo(mStoppedState);
+                    break;
+                case CMD_PRE_DHCP_ACTION_COMPLETE:
+                    if (runDhcp(DhcpAction.RENEW)) {
+                       transitionTo(mRunningState);
+                    } else {
+                       transitionTo(mStoppedState);
+                    }
+                    break;
+                case CMD_START_DHCP:
+                    //ignore
+                    break;
+                default:
+                    retValue = NOT_HANDLED;
+                    break;
+            }
+            return retValue;
+        }
+    }
+
+    private boolean runDhcp(DhcpAction dhcpAction) {
+        boolean success = false;
+        DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
+
+        if (dhcpAction == DhcpAction.START) {
+            Log.d(TAG, "DHCP request on " + mInterfaceName);
+            success = NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal);
+        } else if (dhcpAction == DhcpAction.RENEW) {
+            Log.d(TAG, "DHCP renewal on " + mInterfaceName);
+            success = NetworkUtils.runDhcpRenew(mInterfaceName, dhcpInfoInternal);
+        }
+
+        if (success) {
+            Log.d(TAG, "DHCP succeeded on " + mInterfaceName);
+            //Do it a bit earlier than half the lease duration time
+            //to beat the native DHCP client and avoid extra packets
+            //48% for one hour lease time = 29 minutes
+            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                    SystemClock.elapsedRealtime() +
+                    dhcpInfoInternal.leaseDuration * 480, //in milliseconds
+                    mDhcpRenewalIntent);
+
+            mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpInfoInternal)
+                .sendToTarget();
+        } else {
+            Log.d(TAG, "DHCP failed on " + mInterfaceName + ": " +
+                    NetworkUtils.getDhcpError());
+            NetworkUtils.stopDhcp(mInterfaceName);
+            mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0)
+                .sendToTarget();
+        }
+        return success;
+    }
+}
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index e88292f..61acf2b 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -54,7 +54,7 @@
     String mIfaceName;
     private Collection<LinkAddress> mLinkAddresses;
     private Collection<InetAddress> mDnses;
-    private Collection<InetAddress> mGateways;
+    private Collection<RouteInfo> mRoutes;
     private ProxyProperties mHttpProxy;
 
     public LinkProperties() {
@@ -67,7 +67,7 @@
             mIfaceName = source.getInterfaceName();
             mLinkAddresses = source.getLinkAddresses();
             mDnses = source.getDnses();
-            mGateways = source.getGateways();
+            mRoutes = source.getRoutes();
             mHttpProxy = new ProxyProperties(source.getHttpProxy());
         }
     }
@@ -104,11 +104,11 @@
         return Collections.unmodifiableCollection(mDnses);
     }
 
-    public void addGateway(InetAddress gateway) {
-        if (gateway != null) mGateways.add(gateway);
+    public void addRoute(RouteInfo route) {
+        if (route != null) mRoutes.add(route);
     }
-    public Collection<InetAddress> getGateways() {
-        return Collections.unmodifiableCollection(mGateways);
+    public Collection<RouteInfo> getRoutes() {
+        return Collections.unmodifiableCollection(mRoutes);
     }
 
     public void setHttpProxy(ProxyProperties proxy) {
@@ -122,7 +122,7 @@
         mIfaceName = null;
         mLinkAddresses = new ArrayList<LinkAddress>();
         mDnses = new ArrayList<InetAddress>();
-        mGateways = new ArrayList<InetAddress>();
+        mRoutes = new ArrayList<RouteInfo>();
         mHttpProxy = null;
     }
 
@@ -146,12 +146,12 @@
         for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ",";
         dns += "] ";
 
-        String gateways = "Gateways: [";
-        for (InetAddress gw : mGateways) gateways += gw.getHostAddress() + ",";
-        gateways += "] ";
+        String routes = "Routes: [";
+        for (RouteInfo route : mRoutes) routes += route.toString() + ",";
+        routes += "] ";
         String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " ");
 
-        return ifaceName + linkAddresses + gateways + dns + proxy;
+        return ifaceName + linkAddresses + routes + dns + proxy;
     }
 
 
@@ -177,7 +177,7 @@
 
         boolean sameAddresses;
         boolean sameDnses;
-        boolean sameGateways;
+        boolean sameRoutes;
 
         LinkProperties target = (LinkProperties) obj;
 
@@ -190,12 +190,12 @@
         sameDnses = (mDnses.size() == targetDnses.size()) ?
                 mDnses.containsAll(targetDnses) : false;
 
-        Collection<InetAddress> targetGateways = target.getGateways();
-        sameGateways = (mGateways.size() == targetGateways.size()) ?
-                mGateways.containsAll(targetGateways) : false;
+        Collection<RouteInfo> targetRoutes = target.getRoutes();
+        sameRoutes = (mRoutes.size() == targetRoutes.size()) ?
+                mRoutes.containsAll(targetRoutes) : false;
 
         return
-            sameAddresses && sameDnses && sameGateways
+            sameAddresses && sameDnses && sameRoutes
             && TextUtils.equals(getInterfaceName(), target.getInterfaceName())
             && (getHttpProxy() == null ? target.getHttpProxy() == null :
                 getHttpProxy().equals(target.getHttpProxy()));
@@ -211,7 +211,7 @@
         return ((null == mIfaceName) ? 0 : mIfaceName.hashCode()
                 + mLinkAddresses.size() * 31
                 + mDnses.size() * 37
-                + mGateways.size() * 41
+                + mRoutes.size() * 41
                 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode()));
     }
 
@@ -231,9 +231,9 @@
             dest.writeByteArray(d.getAddress());
         }
 
-        dest.writeInt(mGateways.size());
-        for(InetAddress gw : mGateways) {
-            dest.writeByteArray(gw.getAddress());
+        dest.writeInt(mRoutes.size());
+        for(RouteInfo route : mRoutes) {
+            dest.writeParcelable(route, flags);
         }
 
         if (mHttpProxy != null) {
@@ -272,9 +272,7 @@
                 }
                 addressCount = in.readInt();
                 for (int i=0; i<addressCount; i++) {
-                    try {
-                        netProp.addGateway(InetAddress.getByAddress(in.createByteArray()));
-                    } catch (UnknownHostException e) { }
+                    netProp.addRoute((RouteInfo)in.readParcelable(null));
                 }
                 if (in.readByte() == 1) {
                     netProp.setHttpProxy((ProxyProperties)in.readParcelable(null));
diff --git a/core/java/android/net/NetworkConfig.java b/core/java/android/net/NetworkConfig.java
index 6e774a6..3cc0bc5 100644
--- a/core/java/android/net/NetworkConfig.java
+++ b/core/java/android/net/NetworkConfig.java
@@ -50,6 +50,13 @@
     public boolean dependencyMet;
 
     /**
+     * indicates the default restoral timer in seconds
+     * if the network is used as a special network feature
+     * -1 indicates no restoration of default
+     */
+    public int restoreTime;
+
+    /**
      * input string from config.xml resource.  Uses the form:
      * [Connection name],[ConnectivityManager connection type],
      * [associated radio-type],[priority],[dependencyMet]
@@ -60,7 +67,8 @@
         type = Integer.parseInt(fragments[1]);
         radio = Integer.parseInt(fragments[2]);
         priority = Integer.parseInt(fragments[3]);
-        dependencyMet = Boolean.parseBoolean(fragments[4]);
+        restoreTime = Integer.parseInt(fragments[4]);
+        dependencyMet = Boolean.parseBoolean(fragments[5]);
     }
 
     /**
diff --git a/core/java/android/net/NetworkStats.aidl b/core/java/android/net/NetworkStats.aidl
new file mode 100644
index 0000000..d06ca65
--- /dev/null
+++ b/core/java/android/net/NetworkStats.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2011, 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.net;
+
+parcelable NetworkStats;
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
new file mode 100644
index 0000000..4430e00
--- /dev/null
+++ b/core/java/android/net/NetworkStats.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2011 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.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+
+import java.io.CharArrayWriter;
+import java.io.PrintWriter;
+
+/**
+ * Collection of network statistics. Can contain summary details across all
+ * interfaces, or details with per-UID granularity. Designed to parcel quickly
+ * across process boundaries.
+ *
+ * @hide
+ */
+public class NetworkStats implements Parcelable {
+    /** {@link #iface} value when entry is summarized over all interfaces. */
+    public static final String IFACE_ALL = null;
+    /** {@link #uid} value when entry is summarized over all UIDs. */
+    public static final int UID_ALL = 0;
+
+    /**
+     * {@link SystemClock#elapsedRealtime()} timestamp when this data was
+     * generated.
+     */
+    public final long elapsedRealtime;
+    public final String[] iface;
+    public final int[] uid;
+    public final long[] rx;
+    public final long[] tx;
+
+    // TODO: add fg/bg stats and tag granularity
+
+    private NetworkStats(long elapsedRealtime, String[] iface, int[] uid, long[] rx, long[] tx) {
+        this.elapsedRealtime = elapsedRealtime;
+        this.iface = iface;
+        this.uid = uid;
+        this.rx = rx;
+        this.tx = tx;
+    }
+
+    public NetworkStats(Parcel parcel) {
+        elapsedRealtime = parcel.readLong();
+        iface = parcel.createStringArray();
+        uid = parcel.createIntArray();
+        rx = parcel.createLongArray();
+        tx = parcel.createLongArray();
+    }
+
+    public static class Builder {
+        private long mElapsedRealtime;
+        private final String[] mIface;
+        private final int[] mUid;
+        private final long[] mRx;
+        private final long[] mTx;
+
+        private int mIndex = 0;
+
+        public Builder(long elapsedRealtime, int size) {
+            mElapsedRealtime = elapsedRealtime;
+            mIface = new String[size];
+            mUid = new int[size];
+            mRx = new long[size];
+            mTx = new long[size];
+        }
+
+        public void addEntry(String iface, int uid, long rx, long tx) {
+            mIface[mIndex] = iface;
+            mUid[mIndex] = uid;
+            mRx[mIndex] = rx;
+            mTx[mIndex] = tx;
+            mIndex++;
+        }
+
+        public NetworkStats build() {
+            if (mIndex != mIface.length) {
+                throw new IllegalArgumentException("unexpected number of entries");
+            }
+            return new NetworkStats(mElapsedRealtime, mIface, mUid, mRx, mTx);
+        }
+    }
+
+    /**
+     * Find first stats index that matches the requested parameters.
+     */
+    public int findIndex(String iface, int uid) {
+        for (int i = 0; i < this.iface.length; i++) {
+            if (equal(iface, this.iface[i]) && uid == this.uid[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    private static boolean equal(Object a, Object b) {
+        return a == b || (a != null && a.equals(b));
+    }
+
+    /** {@inheritDoc} */
+    public int describeContents() {
+        return 0;
+    }
+
+    public void dump(String prefix, PrintWriter pw) {
+        pw.print(prefix);
+        pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
+        for (int i = 0; i < iface.length; i++) {
+            pw.print(prefix);
+            pw.print("  iface="); pw.print(iface[i]);
+            pw.print(" uid="); pw.print(uid[i]);
+            pw.print(" rx="); pw.print(rx[i]);
+            pw.print(" tx="); pw.println(tx[i]);
+        }
+    }
+
+    @Override
+    public String toString() {
+        final CharArrayWriter writer = new CharArrayWriter();
+        dump("", new PrintWriter(writer));
+        return writer.toString();
+    }
+
+    /** {@inheritDoc} */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(elapsedRealtime);
+        dest.writeStringArray(iface);
+        dest.writeIntArray(uid);
+        dest.writeLongArray(rx);
+        dest.writeLongArray(tx);
+    }
+
+    public static final Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
+        public NetworkStats createFromParcel(Parcel in) {
+            return new NetworkStats(in);
+        }
+
+        public NetworkStats[] newArray(int size) {
+            return new NetworkStats[size];
+        }
+    };
+}
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index b3f3988..823d10f 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -80,6 +80,16 @@
     public native static boolean runDhcp(String interfaceName, DhcpInfoInternal ipInfo);
 
     /**
+     * Initiate renewal on the Dhcp client daemon. This call blocks until it obtains
+     * a result (either success or failure) from the daemon.
+     * @param interfaceName the name of the interface to configure
+     * @param ipInfo if the request succeeds, this object is filled in with
+     * the IP address information.
+     * @return {@code true} for success, {@code false} for failure
+     */
+    public native static boolean runDhcpRenew(String interfaceName, DhcpInfoInternal ipInfo);
+
+    /**
      * Shut down the DHCP client daemon.
      * @param interfaceName the name of the interface for which the daemon
      * should be stopped
diff --git a/core/java/android/net/RouteInfo.aidl b/core/java/android/net/RouteInfo.aidl
new file mode 100644
index 0000000..2296a57
--- /dev/null
+++ b/core/java/android/net/RouteInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2011 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.net;
+
+parcelable RouteInfo;
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
new file mode 100644
index 0000000..5b10531
--- /dev/null
+++ b/core/java/android/net/RouteInfo.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2011 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.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.net.UnknownHostException;
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+/**
+ * A simple container for route information.
+ *
+ * @hide
+ */
+public class RouteInfo implements Parcelable {
+    /**
+     * The IP destination address for this route.
+     */
+    private final LinkAddress mDestination;
+
+    /**
+     * The gateway address for this route.
+     */
+    private final InetAddress mGateway;
+
+    private final boolean mIsDefault;
+
+    public RouteInfo(LinkAddress destination, InetAddress gateway) {
+        if (destination == null) {
+            try {
+                if ((gateway != null) && (gateway instanceof Inet4Address)) {
+                    destination = new LinkAddress(InetAddress.getByName("0.0.0.0"), 32);
+                } else {
+                    destination = new LinkAddress(InetAddress.getByName("::0"), 128);
+                }
+            } catch (Exception e) {}
+        }
+        mDestination = destination;
+        mGateway = gateway;
+        mIsDefault = isDefault();
+    }
+
+    public RouteInfo(InetAddress gateway) {
+        LinkAddress destination = null;
+        try {
+            if ((gateway != null) && (gateway instanceof Inet4Address)) {
+                destination = new LinkAddress(InetAddress.getByName("0.0.0.0"), 32);
+            } else {
+                destination = new LinkAddress(InetAddress.getByName("::0"), 128);
+            }
+        } catch (Exception e) {}
+        mDestination = destination;
+        mGateway = gateway;
+        mIsDefault = isDefault();
+    }
+
+    private boolean isDefault() {
+        boolean val = false;
+        if (mGateway != null) {
+            if (mGateway instanceof Inet4Address) {
+                val = (mDestination == null || mDestination.getNetworkPrefixLength() == 32);
+            } else {
+                val = (mDestination == null || mDestination.getNetworkPrefixLength() == 128);
+            }
+        }
+        return val;
+    }
+
+    public LinkAddress getDestination() {
+        return mDestination;
+    }
+
+    public InetAddress getGateway() {
+        return mGateway;
+    }
+
+    public boolean isDefaultRoute() {
+        return mIsDefault;
+    }
+
+    public String toString() {
+        String val = "";
+        if (mDestination != null) val = mDestination.toString();
+        if (mGateway != null) val += " -> " + mGateway.getHostAddress();
+        return val;
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel dest, int flags) {
+        if (mDestination == null) {
+            dest.writeByte((byte) 0);
+        } else {
+            dest.writeByte((byte) 1);
+            dest.writeByteArray(mDestination.getAddress().getAddress());
+            dest.writeInt(mDestination.getNetworkPrefixLength());
+        }
+
+        if (mGateway == null) {
+            dest.writeByte((byte) 0);
+        } else {
+            dest.writeByte((byte) 1);
+            dest.writeByteArray(mGateway.getAddress());
+        }
+    }
+
+    public static final Creator<RouteInfo> CREATOR =
+        new Creator<RouteInfo>() {
+        public RouteInfo createFromParcel(Parcel in) {
+            InetAddress destAddr = null;
+            int prefix = 0;
+            InetAddress gateway = null;
+
+            if (in.readByte() == 1) {
+                byte[] addr = in.createByteArray();
+                prefix = in.readInt();
+
+                try {
+                    destAddr = InetAddress.getByAddress(addr);
+                } catch (UnknownHostException e) {}
+            }
+
+            if (in.readByte() == 1) {
+                byte[] addr = in.createByteArray();
+
+                try {
+                    gateway = InetAddress.getByAddress(addr);
+                } catch (UnknownHostException e) {}
+            }
+
+            LinkAddress dest = null;
+
+            if (destAddr != null) {
+                dest = new LinkAddress(destAddr, prefix);
+            }
+
+            return new RouteInfo(dest, gateway);
+        }
+
+        public RouteInfo[] newArray(int size) {
+            return new RouteInfo[size];
+        }
+    };
+}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index b0f3ac3..e344197 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2080,7 +2080,6 @@
         final int NU = uidStats.size();
         boolean didPid = false;
         long nowRealtime = SystemClock.elapsedRealtime();
-        StringBuilder sb = new StringBuilder(64);
         for (int i=0; i<NU; i++) {
             Uid uid = uidStats.valueAt(i);
             SparseArray<? extends Uid.Pid> pids = uid.getPidStats();
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 212c5fb..fe36786 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -19,6 +19,7 @@
 
 import android.net.InterfaceConfiguration;
 import android.net.INetworkManagementEventObserver;
+import android.net.NetworkStats;
 import android.net.wifi.WifiConfiguration;
 
 /**
@@ -65,7 +66,6 @@
      ** TETHERING RELATED
      **/
 
-
     /**
      * Returns true if IP forwarding is enabled
      */
@@ -181,17 +181,23 @@
     void setAccessPoint(in WifiConfiguration wifiConfig, String wlanIface, String softapIface);
 
     /**
-     * Read number of bytes sent over an interface
-     */
-    long getInterfaceTxCounter(String iface);
+     ** DATA USAGE RELATED
+     **/
 
     /**
-     * Read number of bytes received over an interface
+     * Return global network statistics summarized at an interface level,
+     * without any UID-level granularity.
      */
-    long getInterfaceRxCounter(String iface);
+    NetworkStats getNetworkStatsSummary();
 
     /**
-     * Configures bandwidth throttling on an interface
+     * Return detailed network statistics with UID-level granularity,
+     * including interface and tag details.
+     */
+    NetworkStats getNetworkStatsDetail();
+
+    /**
+     * Configures bandwidth throttling on an interface.
      */
     void setInterfaceThrottle(String iface, int rxKbps, int txKbps);
 
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index c830f7a..a17983a 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -261,16 +261,10 @@
         public void acquire()
         {
             synchronized (mToken) {
-                if (!mRefCounted || mCount++ == 0) {
-                    try {
-                        mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource);
-                    } catch (RemoteException e) {
-                    }
-                    mHeld = true;
-                }
+                acquireLocked();
             }
         }
-        
+
         /**
          * Makes sure the device is on at the level you asked when you created
          * the wake lock. The lock will be released after the given timeout.
@@ -278,10 +272,22 @@
          * @param timeout Release the lock after the give timeout in milliseconds.
          */
         public void acquire(long timeout) {
-            acquire();
-            mHandler.postDelayed(mReleaser, timeout);
+            synchronized (mToken) {
+                acquireLocked();
+                mHandler.postDelayed(mReleaser, timeout);
+            }
         }
         
+        private void acquireLocked() {
+            if (!mRefCounted || mCount++ == 0) {
+                mHandler.removeCallbacks(mReleaser);
+                try {
+                    mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource);
+                } catch (RemoteException e) {
+                }
+                mHeld = true;
+            }
+        }
 
         /**
          * Release your claim to the CPU or screen being on.
@@ -290,8 +296,7 @@
          * It may turn off shortly after you release it, or it may not if there
          * are other wake locks held.
          */
-        public void release()
-        {
+        public void release() {
             release(0);
         }
 
@@ -306,9 +311,9 @@
          *
          * {@hide}
          */
-        public void release(int flags)
-        {
+        public void release(int flags) {
             synchronized (mToken) {
+                mHandler.removeCallbacks(mReleaser);
                 if (!mRefCounted || --mCount == 0) {
                     try {
                         mService.releaseWakeLock(mToken, flags);
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index 309a5ec..2eeb7a4 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -441,6 +441,35 @@
          * <P>Type: INTEGER</P>
          */
         public static final String MAX_REMINDERS = "maxReminders";
+
+        /**
+         * These fields are only writable by a sync adapter. To modify them the
+         * caller must include CALLER_IS_SYNCADAPTER, _SYNC_ACCOUNT, and
+         * _SYNC_ACCOUNT_TYPE in the query parameters.
+         */
+        public static final String[] SYNC_WRITABLE_COLUMNS = new String[] {
+            _SYNC_ACCOUNT,
+            _SYNC_ACCOUNT_TYPE,
+            _SYNC_ID,
+            _SYNC_TIME,
+            _SYNC_VERSION,
+            _SYNC_DIRTY,
+            OWNER_ACCOUNT,
+            MAX_REMINDERS,
+            CAN_MODIFY_TIME_ZONE,
+            CAN_ORGANIZER_RESPOND,
+            LOCATION,
+            TIMEZONE,
+            ACCESS_LEVEL,
+            DELETED,
+            SYNC1,
+            SYNC2,
+            SYNC3,
+            SYNC4,
+            SYNC5,
+            SYNC6,
+            SYNC_STATE,
+        };
     }
 
     /**
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 20661d7..eae7574 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -51,7 +51,7 @@
 import android.view.SurfaceHolder;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
 import android.view.WindowManagerPolicy;
@@ -650,7 +650,7 @@
             mWindowToken = wrapper.mWindowToken;
             mSurfaceHolder.setSizeFromLayout();
             mInitializing = true;
-            mSession = ViewRoot.getWindowSession(getMainLooper());
+            mSession = ViewAncestor.getWindowSession(getMainLooper());
             
             mWindow.setSession(mSession);
             
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index ac5db62..6741059 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -629,10 +629,16 @@
         public CharSequence createFromParcel(Parcel p) {
             int kind = p.readInt();
 
-            if (kind == 1)
-                return p.readString();
+            String string = p.readString();
+            if (string == null) {
+                return null;
+            }
 
-            SpannableString sp = new SpannableString(p.readString());
+            if (kind == 1) {
+                return string;
+            }
+
+            SpannableString sp = new SpannableString(string);
 
             while (true) {
                 kind = p.readInt();
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java
index 729c506..5b19ecd 100644
--- a/core/java/android/util/NtpTrustedTime.java
+++ b/core/java/android/util/NtpTrustedTime.java
@@ -45,7 +45,8 @@
     /** {@inheritDoc} */
     public boolean forceRefresh() {
         if (mNtpServer == null) {
-            throw new IllegalStateException("Missing NTP server");
+            // missing server, so no trusted time available
+            return false;
         }
 
         final SntpClient client = new SntpClient();
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index cdf8954..2b79a76 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -163,8 +163,7 @@
     static native int nCreateTextureLayer(int[] layerInfo);
     static native int nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo);
     static native void nResizeLayer(int layerId, int width, int height, int[] layerInfo);
-    static native void nUpdateTextureLayer(int layerId, int width, int height,
-            float[] textureTransform);
+    static native void nUpdateTextureLayer(int layerId, int width, int height, int surface);
     static native void nDestroyLayer(int layerId);
     static native void nDestroyLayerDeferred(int layerId);
 
@@ -262,6 +261,13 @@
     private static native boolean nDrawDisplayList(int renderer, int displayList,
             int width, int height, Rect dirty);
 
+    @Override
+    void outputDisplayList(DisplayList displayList) {
+        nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).mNativeDisplayList);
+    }
+
+    private static native void nOutputDisplayList(int renderer, int displayList);
+
     ///////////////////////////////////////////////////////////////////////////
     // Hardware layer
     ///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java
index 21fbdfcf6..fcf421b 100644
--- a/core/java/android/view/GLES20TextureLayer.java
+++ b/core/java/android/view/GLES20TextureLayer.java
@@ -70,7 +70,7 @@
         return mSurface;
     }
 
-    void update(int width, int height, float[] textureTransform) {
-        GLES20Canvas.nUpdateTextureLayer(mLayer, width, height, textureTransform);
+    void update(int width, int height, int surface) {
+        GLES20Canvas.nUpdateTextureLayer(mLayer, width, height, surface);
     }
 }
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index caa7b74..23b3abc 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -64,6 +64,14 @@
     abstract boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty);
 
     /**
+     * Outputs the specified display list to the log. This method exists for use by
+     * tools to output display lists for selected nodes to the log.
+     *
+     * @param displayList The display list to be logged.
+     */
+    abstract void outputDisplayList(DisplayList displayList);
+
+    /**
      * Draws the specified layer onto this canvas.
      *
      * @param layer The layer to composite on this canvas
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 5b2983d..845fbc3 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -34,7 +34,7 @@
 import javax.microedition.khronos.opengles.GL;
 
 /**
- * Interface for rendering a ViewRoot using hardware acceleration.
+ * Interface for rendering a ViewAncestor using hardware acceleration.
  * 
  * @hide
  */
@@ -202,15 +202,14 @@
      * @param layer The hardware layer to update
      * @param width The layer's width
      * @param height The layer's height
-     * @param textureTransform A 4x4 column-first transform matrix to apply to
-     *        texture coordinates
+     * @param surface The surface to update
      */
     abstract void updateTextureLayer(HardwareLayer layer, int width, int height,
-            float[] textureTransform);    
+            SurfaceTexture surface);    
     
     /**
      * Initializes the hardware renderer for the specified surface and setup the
-     * renderer for drawing, if needed. This is invoked when the ViewRoot has
+     * renderer for drawing, if needed. This is invoked when the ViewAncestor has
      * potentially lost the hardware renderer. The hardware renderer should be
      * reinitialized and setup when the render {@link #isRequested()} and
      * {@link #isEnabled()}.
@@ -289,9 +288,10 @@
     @SuppressWarnings({"deprecation"})
     static abstract class GlRenderer extends HardwareRenderer {
         // These values are not exposed in our EGL APIs
-        private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
-        private static final int EGL_SURFACE_TYPE = 0x3033;
-        private static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
+        static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+        static final int EGL_SURFACE_TYPE = 0x3033;
+        static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
+        static final int EGL_OPENGL_ES2_BIT = 4;
 
         private static final int SURFACE_STATE_ERROR = 0;
         private static final int SURFACE_STATE_SUCCESS = 1;
@@ -459,13 +459,12 @@
                         getEGLErrorString(sEgl.eglGetError()));
             }
 
-            sEglConfig = getConfigChooser(mGlVersion).chooseConfig(sEgl, sEglDisplay);
+            sEglConfig = chooseEglConfig();
             if (sEglConfig == null) {
                 // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without
                 if (mDirtyRegions) {
                     mDirtyRegions = false;
-
-                    sEglConfig = getConfigChooser(mGlVersion).chooseConfig(sEgl, sEglDisplay);
+                    sEglConfig = chooseEglConfig();
                     if (sEglConfig == null) {
                         throw new RuntimeException("eglConfig not initialized");
                     }
@@ -481,6 +480,21 @@
             sEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
         }
 
+        private EGLConfig chooseEglConfig() {
+            int[] configsCount = new int[1];
+            EGLConfig[] configs = new EGLConfig[1];
+            int[] configSpec = getConfig(mDirtyRegions);
+            if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) {
+                throw new IllegalArgumentException("eglChooseConfig failed " +
+                        getEGLErrorString(sEgl.eglGetError()));
+            } else if (configsCount[0] > 0) {
+                return configs[0];
+            }
+            return null;
+        }
+
+        abstract int[] getConfig(boolean dirtyRegions);
+
         GL createEglSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException {
             // Check preconditions.
             if (sEgl == null) {
@@ -592,15 +606,6 @@
 
         void onPostDraw() {
         }
-        
-        /**
-         * Defines the EGL configuration for this renderer.
-         * 
-         * @return An {@link android.view.HardwareRenderer.GlRenderer.EglConfigChooser}.
-         */
-        EglConfigChooser getConfigChooser(int glVersion) {
-            return new ComponentSizeChooser(glVersion, 8, 8, 8, 8, 0, 0, mDirtyRegions);
-        }
 
         @Override
         void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
@@ -713,134 +718,6 @@
             }
             return SURFACE_STATE_SUCCESS;
         }
-
-        static abstract class EglConfigChooser {
-            final int[] mConfigSpec;
-            private final int mGlVersion;
-
-            EglConfigChooser(int glVersion, int[] configSpec) {
-                mGlVersion = glVersion;
-                mConfigSpec = filterConfigSpec(configSpec);
-            }
-
-            EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
-                int[] index = new int[1];
-                if (!egl.eglChooseConfig(display, mConfigSpec, null, 0, index)) {
-                    throw new IllegalArgumentException("eglChooseConfig failed "
-                            + getEGLErrorString(egl.eglGetError()));
-                }
-
-                int numConfigs = index[0];
-                if (numConfigs <= 0) {
-                    throw new IllegalArgumentException("No configs match configSpec");
-                }
-
-                EGLConfig[] configs = new EGLConfig[numConfigs];
-                if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, index)) {
-                    throw new IllegalArgumentException("eglChooseConfig failed "
-                            + getEGLErrorString(egl.eglGetError()));
-                }
-
-                EGLConfig config = chooseConfig(egl, display, configs);
-                if (config == null) {
-                    throw new IllegalArgumentException("No config chosen");
-                }
-
-                return config;
-            }
-
-            abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs);
-
-            private int[] filterConfigSpec(int[] configSpec) {
-                if (mGlVersion != 2) {
-                    return configSpec;
-                }
-                /* We know none of the subclasses define EGL_RENDERABLE_TYPE.
-                 * And we know the configSpec is well formed.
-                 */
-                int len = configSpec.length;
-                int[] newConfigSpec = new int[len + 2];
-                System.arraycopy(configSpec, 0, newConfigSpec, 0, len - 1);
-                newConfigSpec[len - 1] = EGL10.EGL_RENDERABLE_TYPE;
-                newConfigSpec[len] = 4; /* EGL_OPENGL_ES2_BIT */
-                newConfigSpec[len + 1] = EGL10.EGL_NONE;
-                return newConfigSpec;
-            }
-        }
-
-        /**
-         * Choose a configuration with exactly the specified r,g,b,a sizes,
-         * and at least the specified depth and stencil sizes.
-         */
-        static class ComponentSizeChooser extends EglConfigChooser {
-            private int[] mValue;
-
-            private final int mRedSize;
-            private final int mGreenSize;
-            private final int mBlueSize;
-            private final int mAlphaSize;
-            private final int mDepthSize;
-            private final int mStencilSize;
-            private final boolean mDirtyRegions;
-
-            ComponentSizeChooser(int glVersion, int redSize, int greenSize, int blueSize,
-                    int alphaSize, int depthSize, int stencilSize, boolean dirtyRegions) {
-                super(glVersion, new int[] {
-                        EGL10.EGL_RED_SIZE, redSize,
-                        EGL10.EGL_GREEN_SIZE, greenSize,
-                        EGL10.EGL_BLUE_SIZE, blueSize,
-                        EGL10.EGL_ALPHA_SIZE, alphaSize,
-                        EGL10.EGL_DEPTH_SIZE, depthSize,
-                        EGL10.EGL_STENCIL_SIZE, stencilSize,
-                        EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT |
-                                (dirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
-                        EGL10.EGL_NONE });
-                mValue = new int[1];
-                mRedSize = redSize;
-                mGreenSize = greenSize;
-                mBlueSize = blueSize;
-                mAlphaSize = alphaSize;
-                mDepthSize = depthSize;
-                mStencilSize = stencilSize;
-                mDirtyRegions = dirtyRegions;
-            }
-
-            @Override
-            EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {
-                for (EGLConfig config : configs) {
-                    int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0);
-                    int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0);
-                    if (d >= mDepthSize && s >= mStencilSize) {
-                        int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0);
-                        int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0);
-                        int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);
-                        int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);
-                        boolean backBuffer;
-                        if (mDirtyRegions) {
-                            int surfaceType = findConfigAttrib(egl, display, config,
-                                    EGL_SURFACE_TYPE, 0);
-                            backBuffer = (surfaceType & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) != 0;
-                        } else {
-                            backBuffer = true;
-                        }
-                        if (r >= mRedSize && g >= mGreenSize && b >= mBlueSize && a >= mAlphaSize
-                                && backBuffer) {
-                            return config;
-                        }
-                    }
-                }
-                return null;
-            }
-
-            private int findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config,
-                    int attribute, int defaultValue) {
-                if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
-                    return mValue[0];
-                }
-
-                return defaultValue;
-            }
-        }
     }
 
     /**
@@ -857,7 +734,23 @@
         GLES20Canvas createCanvas() {
             return mGlCanvas = new GLES20Canvas(mTranslucent);
         }
-        
+
+        @Override
+        int[] getConfig(boolean dirtyRegions) {
+            return new int[] {
+                    EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+                    EGL10.EGL_RED_SIZE, 8,
+                    EGL10.EGL_GREEN_SIZE, 8,
+                    EGL10.EGL_BLUE_SIZE, 8,
+                    EGL10.EGL_ALPHA_SIZE, 8,
+                    EGL10.EGL_DEPTH_SIZE, 0,
+                    EGL10.EGL_STENCIL_SIZE, 0,
+                    EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT |
+                            (dirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
+                    EGL10.EGL_NONE
+            };
+        }
+
         @Override
         boolean canDraw() {
             return super.canDraw() && mGlCanvas != null;
@@ -906,8 +799,8 @@
 
         @Override
         void updateTextureLayer(HardwareLayer layer, int width, int height,
-                float[] textureTransform) {
-            ((GLES20TextureLayer) layer).update(width, height, textureTransform);
+                SurfaceTexture surface) {
+            ((GLES20TextureLayer) layer).update(width, height, surface.mSurfaceTexture);
         }
 
         static HardwareRenderer create(boolean translucent) {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 0a7a375..a98c669 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -427,7 +427,7 @@
         if (!mHaveFrame) {
             return;
         }
-        ViewRoot viewRoot = (ViewRoot) getRootView().getParent();
+        ViewAncestor viewRoot = (ViewAncestor) getRootView().getParent();
         if (viewRoot != null) {
             mTranslator = viewRoot.mTranslator;
         }
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 6380e1b..755ecf5 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -73,6 +73,10 @@
  *              // Something bad happened
  *          }
  *      }
+ *      
+ *      public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+ *          // Ignored, Camera does all the work for us
+ *      }
  *  }
  * </pre>
  * 
@@ -90,8 +94,6 @@
     private HardwareLayer mLayer;
     private SurfaceTexture mSurface;
     private SurfaceTextureListener mListener;
-    
-    private final float[] mTextureTransform = new float[16];
 
     private final Runnable mUpdateLayerAction = new Runnable() {
         @Override
@@ -99,6 +101,7 @@
             updateLayer();
         }
     };
+    private SurfaceTexture.OnFrameAvailableListener mUpdateListener;
 
     /**
      * Creates a new TextureView.
@@ -210,6 +213,14 @@
     }
 
     @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        if (mSurface != null) {
+            nSetDefaultBufferSize(mSurface.mSurfaceTexture, getWidth(), getHeight());
+        }
+    }
+
+    @Override
     HardwareLayer getHardwareLayer() {
         if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
             return null;
@@ -218,15 +229,17 @@
         if (mLayer == null) {
             mLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer();
             mSurface = mAttachInfo.mHardwareRenderer.createSuraceTexture(mLayer);
+            nSetDefaultBufferSize(mSurface.mSurfaceTexture, getWidth(), getHeight());
 
-            mSurface.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
+            mUpdateListener = new SurfaceTexture.OnFrameAvailableListener() {
                 @Override
                 public void onFrameAvailable(SurfaceTexture surfaceTexture) {
                     // Per SurfaceTexture's documentation, the callback may be invoked
                     // from an arbitrary thread
                     post(mUpdateLayerAction);
                 }
-            });
+            };
+            mSurface.setOnFrameAvailableListener(mUpdateListener);
 
             if (mListener != null) {
                 mListener.onSurfaceTextureAvailable(mSurface);
@@ -236,16 +249,29 @@
         return mLayer;
     }
 
+    @Override
+    protected void onVisibilityChanged(View changedView, int visibility) {
+        super.onVisibilityChanged(changedView, visibility);
+
+        if (mSurface != null) {
+            // When the view becomes invisible, stop updating it, it's a waste of CPU
+            // To cancel updates, the easiest thing to do is simply to remove the
+            // updates listener
+            if (visibility == VISIBLE) {
+                mSurface.setOnFrameAvailableListener(mUpdateListener);
+                updateLayer();
+            } else {
+                mSurface.setOnFrameAvailableListener(null);
+            }
+        }
+    }
+
     private void updateLayer() {
         if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
             return;
         }
 
-        mSurface.updateTexImage();
-        mSurface.getTransformMatrix(mTextureTransform);
-
-        mAttachInfo.mHardwareRenderer.updateTextureLayer(mLayer, getWidth(), getHeight(),
-                mTextureTransform);
+        mAttachInfo.mHardwareRenderer.updateTextureLayer(mLayer, getWidth(), getHeight(), mSurface);
 
         invalidate();
     }
@@ -292,5 +318,17 @@
          *                {@link android.view.TextureView#getSurfaceTexture()}
          */
         public void onSurfaceTextureAvailable(SurfaceTexture surface);
+
+        /**
+         * Invoked when the {@link SurfaceTexture}'s buffers size changed.
+         * 
+         * @param surface The surface returned by
+         *                {@link android.view.TextureView#getSurfaceTexture()}
+         * @param width The new width of the surface
+         * @param height The new height of the surface
+         */
+        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height);
     }
+
+    private static native void nSetDefaultBufferSize(int surfaceTexture, int width, int height);
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5af2e56..791ffb9 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4496,10 +4496,10 @@
         return true;
     }
 
-    /** Gets the ViewRoot, or null if not attached. */
-    /*package*/ ViewRoot getViewRoot() {
+    /** Gets the ViewAncestor, or null if not attached. */
+    /*package*/ ViewAncestor getViewAncestor() {
         View root = getRootView();
-        return root != null ? (ViewRoot)root.getParent() : null;
+        return root != null ? (ViewAncestor)root.getParent() : null;
     }
 
     /**
@@ -4515,7 +4515,7 @@
     public final boolean requestFocusFromTouch() {
         // Leave touch mode if we need to
         if (isInTouchMode()) {
-            ViewRoot viewRoot = getViewRoot();
+            ViewAncestor viewRoot = getViewAncestor();
             if (viewRoot != null) {
                 viewRoot.ensureTouchMode(false);
             }
@@ -5083,7 +5083,7 @@
         if (mAttachInfo != null) {
             return mAttachInfo.mInTouchMode;
         } else {
-            return ViewRoot.isInTouchMode();
+            return ViewAncestor.isInTouchMode();
         }
     }
 
@@ -5138,9 +5138,7 @@
                         (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) &&
                         (event.getRepeatCount() == 0)) {
                     setPressed(true);
-                    if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) {
-                        postCheckForLongClick(0);
-                    }
+                    checkForLongClick(0);
                     return true;
                 }
                 break;
@@ -5535,12 +5533,33 @@
                     break;
 
                 case MotionEvent.ACTION_DOWN:
-                    if (mPendingCheckForTap == null) {
-                        mPendingCheckForTap = new CheckForTap();
-                    }
-                    mPrivateFlags |= PREPRESSED;
                     mHasPerformedLongPress = false;
-                    postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
+
+                    // Walk up the hierarchy to determine if we're inside a scrolling container.
+                    boolean isInScrollingContainer = false;
+                    ViewParent p = getParent();
+                    while (p != null && p instanceof ViewGroup) {
+                        if (((ViewGroup) p).shouldDelayChildPressedState()) {
+                            isInScrollingContainer = true;
+                            break;
+                        }
+                        p = p.getParent();
+                    }
+
+                    // For views inside a scrolling container, delay the pressed feedback for
+                    // a short period in case this is a scroll.
+                    if (isInScrollingContainer) {
+                        mPrivateFlags |= PREPRESSED;
+                        if (mPendingCheckForTap == null) {
+                            mPendingCheckForTap = new CheckForTap();
+                        }
+                        postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
+                    } else {
+                        // Not inside a scrolling container, so show the feedback right away
+                        mPrivateFlags |= PRESSED;
+                        refreshDrawableState();
+                        checkForLongClick(0);
+                    }
                     break;
 
                 case MotionEvent.ACTION_CANCEL:
@@ -7311,7 +7330,7 @@
             if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
                 if (p != null && ai != null && ai.mHardwareAccelerated) {
                     // fast-track for GL-enabled applications; just invalidate the whole hierarchy
-                    // with a null dirty rect, which tells the ViewRoot to redraw everything
+                    // with a null dirty rect, which tells the ViewAncestor to redraw everything
                     p.invalidateChild(this, null);
                     return;
                 }
@@ -7354,7 +7373,7 @@
             if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
                 if (p != null && ai != null && ai.mHardwareAccelerated) {
                     // fast-track for GL-enabled applications; just invalidate the whole hierarchy
-                    // with a null dirty rect, which tells the ViewRoot to redraw everything
+                    // with a null dirty rect, which tells the ViewAncestor to redraw everything
                     p.invalidateChild(this, null);
                     return;
                 }
@@ -7409,7 +7428,7 @@
             if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
                 if (p != null && ai != null && ai.mHardwareAccelerated) {
                     // fast-track for GL-enabled applications; just invalidate the whole hierarchy
-                    // with a null dirty rect, which tells the ViewRoot to redraw everything
+                    // with a null dirty rect, which tells the ViewAncestor to redraw everything
                     p.invalidateChild(this, null);
                     return;
                 }
@@ -7558,7 +7577,7 @@
             handler = attachInfo.mHandler;
         } else {
             // Assume that post will succeed later
-            ViewRoot.getRunQueue().post(action);
+            ViewAncestor.getRunQueue().post(action);
             return true;
         }
 
@@ -7588,7 +7607,7 @@
             handler = attachInfo.mHandler;
         } else {
             // Assume that post will succeed later
-            ViewRoot.getRunQueue().postDelayed(action, delayMillis);
+            ViewAncestor.getRunQueue().postDelayed(action, delayMillis);
             return true;
         }
 
@@ -7612,7 +7631,7 @@
             handler = attachInfo.mHandler;
         } else {
             // Assume that post will succeed later
-            ViewRoot.getRunQueue().removeCallbacks(action);
+            ViewAncestor.getRunQueue().removeCallbacks(action);
             return true;
         }
 
@@ -10593,9 +10612,9 @@
             viewParent = view.mParent;
         }
 
-        if (viewParent instanceof ViewRoot) {
+        if (viewParent instanceof ViewAncestor) {
             // *cough*
-            final ViewRoot vr = (ViewRoot)viewParent;
+            final ViewAncestor vr = (ViewAncestor)viewParent;
             location[1] -= vr.mCurScrollY;
         }
     }
@@ -11405,7 +11424,7 @@
      * therefore all View objects remove themselves from the global transparent
      * region (passed as a parameter to this function).
      *
-     * @param region The transparent region for this ViewRoot (window).
+     * @param region The transparent region for this ViewAncestor (window).
      *
      * @return Returns true if the effective visibility of the view at this
      * point is opaque, regardless of the transparent region; returns false
@@ -11711,7 +11730,7 @@
                     surface.unlockCanvasAndPost(canvas);
                 }
 
-                final ViewRoot root = getViewRoot();
+                final ViewAncestor root = getViewAncestor();
 
                 // Cache the local state object for delivery with DragEvents
                 root.setLocalDragState(myLocalState);
@@ -11846,15 +11865,17 @@
         }
     }
 
-    private void postCheckForLongClick(int delayOffset) {
-        mHasPerformedLongPress = false;
+    private void checkForLongClick(int delayOffset) {
+        if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) {
+            mHasPerformedLongPress = false;
 
-        if (mPendingCheckForLongPress == null) {
-            mPendingCheckForLongPress = new CheckForLongPress();
+            if (mPendingCheckForLongPress == null) {
+                mPendingCheckForLongPress = new CheckForLongPress();
+            }
+            mPendingCheckForLongPress.rememberWindowAttachCount();
+            postDelayed(mPendingCheckForLongPress,
+                    ViewConfiguration.getLongPressTimeout() - delayOffset);
         }
-        mPendingCheckForLongPress.rememberWindowAttachCount();
-        postDelayed(mPendingCheckForLongPress,
-                ViewConfiguration.getLongPressTimeout() - delayOffset);
     }
 
     /**
@@ -12166,9 +12187,7 @@
             mPrivateFlags &= ~PREPRESSED;
             mPrivateFlags |= PRESSED;
             refreshDrawableState();
-            if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) {
-                postCheckForLongClick(ViewConfiguration.getTapTimeout());
-            }
+            checkForLongClick(ViewConfiguration.getTapTimeout());
         }
     }
 
@@ -12497,7 +12516,7 @@
         boolean mScalingRequired;
 
         /**
-         * If set, ViewRoot doesn't use its lame animation for when the window resizes.
+         * If set, ViewAncestor doesn't use its lame animation for when the window resizes.
          */
         boolean mTurnOffWindowResizeAnim;
 
@@ -12576,7 +12595,7 @@
         boolean mInTouchMode;
 
         /**
-         * Indicates that ViewRoot should trigger a global layout change
+         * Indicates that ViewAncestor should trigger a global layout change
          * the next time it performs a traversal
          */
         boolean mRecomputeGlobalAttributes;
@@ -12638,7 +12657,7 @@
         Canvas mCanvas;
 
         /**
-         * A Handler supplied by a view's {@link android.view.ViewRoot}. This
+         * A Handler supplied by a view's {@link android.view.ViewAncestor}. This
          * handler can be used to pump events in the UI events queue.
          */
         final Handler mHandler;
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewAncestor.java
similarity index 98%
rename from core/java/android/view/ViewRoot.java
rename to core/java/android/view/ViewAncestor.java
index f02daba..8085ea8 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewAncestor.java
@@ -82,9 +82,9 @@
  * {@hide}
  */
 @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
-public final class ViewRoot extends Handler implements ViewParent,
+public final class ViewAncestor extends Handler implements ViewParent,
         View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
-    private static final String TAG = "ViewRoot";
+    private static final String TAG = "ViewAncestor";
     private static final boolean DBG = false;
     private static final boolean SHOW_FPS = false;
     private static final boolean LOCAL_LOGV = false;
@@ -273,7 +273,7 @@
         }
     }
     
-    public ViewRoot(Context context) {
+    public ViewAncestor(Context context) {
         super();
 
         if (MEASURE_LATENCY) {
@@ -515,7 +515,7 @@
             }
 
             // Only enable hardware acceleration if we are not in the system process
-            // The window manager creates ViewRoots to display animated preview windows
+            // The window manager creates ViewAncestors to display animated preview windows
             // of launching apps and we don't want those to be hardware accelerated
 
             final boolean systemHwAccelerated =
@@ -1507,6 +1507,20 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    void outputDisplayList(View view) {
+        if (mAttachInfo != null && mAttachInfo.mHardwareCanvas != null) {
+
+            HardwareCanvas canvas = (HardwareCanvas) mAttachInfo.mHardwareCanvas;
+            DisplayList displayList = view.getDisplayList();
+            if (displayList != null) {
+                canvas.outputDisplayList(displayList);
+            }
+        }
+    }
+
     private void draw(boolean fullRedrawNeeded) {
         Surface surface = mSurface;
         if (surface == null || !surface.isValid()) {
@@ -2038,7 +2052,7 @@
             break;
         case DO_TRAVERSAL:
             if (mProfile) {
-                Debug.startMethodTracing("ViewRoot");
+                Debug.startMethodTracing("ViewAncestor");
             }
 
             final long traversalStartTime;
@@ -3546,7 +3560,7 @@
     }
 
     public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
-        // ViewRoot never intercepts touch event, so this can be a no-op
+        // ViewAncestor never intercepts touch event, so this can be a no-op
     }
 
     public boolean requestChildRectangleOnScreen(View child, Rect rectangle,
@@ -3595,14 +3609,14 @@
     }
     
     static class InputMethodCallback extends IInputMethodCallback.Stub {
-        private WeakReference<ViewRoot> mViewRoot;
+        private WeakReference<ViewAncestor> mViewAncestor;
 
-        public InputMethodCallback(ViewRoot viewRoot) {
-            mViewRoot = new WeakReference<ViewRoot>(viewRoot);
+        public InputMethodCallback(ViewAncestor viewRoot) {
+            mViewAncestor = new WeakReference<ViewAncestor>(viewRoot);
         }
 
         public void finishedEvent(int seq, boolean handled) {
-            final ViewRoot viewRoot = mViewRoot.get();
+            final ViewAncestor viewRoot = mViewAncestor.get();
             if (viewRoot != null) {
                 viewRoot.dispatchFinishedEvent(seq, handled);
             }
@@ -3614,36 +3628,36 @@
     }
 
     static class W extends IWindow.Stub {
-        private final WeakReference<ViewRoot> mViewRoot;
+        private final WeakReference<ViewAncestor> mViewAncestor;
 
-        W(ViewRoot viewRoot) {
-            mViewRoot = new WeakReference<ViewRoot>(viewRoot);
+        W(ViewAncestor viewRoot) {
+            mViewAncestor = new WeakReference<ViewAncestor>(viewRoot);
         }
 
         public void resized(int w, int h, Rect coveredInsets, Rect visibleInsets,
                 boolean reportDraw, Configuration newConfig) {
-            final ViewRoot viewRoot = mViewRoot.get();
+            final ViewAncestor viewRoot = mViewAncestor.get();
             if (viewRoot != null) {
                 viewRoot.dispatchResized(w, h, coveredInsets, visibleInsets, reportDraw, newConfig);
             }
         }
 
         public void dispatchAppVisibility(boolean visible) {
-            final ViewRoot viewRoot = mViewRoot.get();
+            final ViewAncestor viewRoot = mViewAncestor.get();
             if (viewRoot != null) {
                 viewRoot.dispatchAppVisibility(visible);
             }
         }
 
         public void dispatchGetNewSurface() {
-            final ViewRoot viewRoot = mViewRoot.get();
+            final ViewAncestor viewRoot = mViewAncestor.get();
             if (viewRoot != null) {
                 viewRoot.dispatchGetNewSurface();
             }
         }
 
         public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
-            final ViewRoot viewRoot = mViewRoot.get();
+            final ViewAncestor viewRoot = mViewAncestor.get();
             if (viewRoot != null) {
                 viewRoot.windowFocusChanged(hasFocus, inTouchMode);
             }
@@ -3663,7 +3677,7 @@
         }
 
         public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
-            final ViewRoot viewRoot = mViewRoot.get();
+            final ViewAncestor viewRoot = mViewAncestor.get();
             if (viewRoot != null) {
                 final View view = viewRoot.mView;
                 if (view != null) {
@@ -3694,7 +3708,7 @@
         }
         
         public void closeSystemDialogs(String reason) {
-            final ViewRoot viewRoot = mViewRoot.get();
+            final ViewAncestor viewRoot = mViewAncestor.get();
             if (viewRoot != null) {
                 viewRoot.dispatchCloseSystemDialogs(reason);
             }
@@ -3722,7 +3736,7 @@
 
         /* Drag/drop */
         public void dispatchDragEvent(DragEvent event) {
-            final ViewRoot viewRoot = mViewRoot.get();
+            final ViewAncestor viewRoot = mViewAncestor.get();
             if (viewRoot != null) {
                 viewRoot.dispatchDragEvent(event);
             }
@@ -3730,7 +3744,7 @@
 
         @Override
         public void dispatchSystemUiVisibilityChanged(int visibility) {
-            final ViewRoot viewRoot = mViewRoot.get();
+            final ViewAncestor viewRoot = mViewAncestor.get();
             if (viewRoot != null) {
                 viewRoot.dispatchSystemUiVisibilityChanged(visibility);
             }
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 94eb429..36bb046 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -95,7 +95,7 @@
      * is a tap or a scroll. If the user does not move within this interval, it is
      * considered to be a tap. 
      */
-    private static final int TAP_TIMEOUT = 115;
+    private static final int TAP_TIMEOUT = 180;
     
     /**
      * Defines the duration in milliseconds we will wait to see if a touch event 
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 881cb76..1534099 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -375,6 +375,7 @@
     private static final String REMOTE_COMMAND_REQUEST_LAYOUT = "REQUEST_LAYOUT";
     private static final String REMOTE_PROFILE = "PROFILE";
     private static final String REMOTE_COMMAND_CAPTURE_LAYERS = "CAPTURE_LAYERS";
+    private static final String REMOTE_COMMAND_OUTPUT_DISPLAYLIST = "OUTPUT_DISPLAYLIST";
 
     private static HashMap<Class<?>, Field[]> sFieldsForClasses;
     private static HashMap<Class<?>, Method[]> sMethodsForClasses;
@@ -395,7 +396,7 @@
     }
 
     private static BufferedWriter sHierarchyTraces;
-    private static ViewRoot sHierarhcyRoot;
+    private static ViewAncestor sHierarhcyRoot;
     private static String sHierarchyTracePrefix;
 
     /**
@@ -434,7 +435,7 @@
     }
 
     private static BufferedWriter sMotionEventTraces;
-    private static ViewRoot sMotionEventRoot;
+    private static ViewAncestor sMotionEventRoot;
     private static String sMotionEventTracePrefix;
 
     /**
@@ -449,14 +450,14 @@
     }
 
     /**
-     * Returns the number of instanciated ViewRoots.
+     * Returns the number of instanciated ViewAncestors.
      *
-     * @return The number of ViewRoots instanciated in the current process.
+     * @return The number of ViewAncestors instanciated in the current process.
      *
      * @hide
      */
-    public static long getViewRootInstanceCount() {
-        return Debug.countInstancesOfClass(ViewRoot.class);
+    public static long getViewAncestorInstanceCount() {
+        return Debug.countInstancesOfClass(ViewAncestor.class);
     }
 
     /**
@@ -670,7 +671,7 @@
             return;
         }
 
-        sHierarhcyRoot = (ViewRoot) view.getRootView().getParent();
+        sHierarhcyRoot = (ViewAncestor) view.getRootView().getParent();
     }
 
     /**
@@ -808,7 +809,7 @@
             return;
         }
 
-        sMotionEventRoot = (ViewRoot) view.getRootView().getParent();
+        sMotionEventRoot = (ViewAncestor) view.getRootView().getParent();
     }
 
     /**
@@ -885,6 +886,8 @@
             final String[] params = parameters.split(" ");
             if (REMOTE_COMMAND_CAPTURE.equalsIgnoreCase(command)) {
                 capture(view, clientStream, params[0]);
+            } else if (REMOTE_COMMAND_OUTPUT_DISPLAYLIST.equalsIgnoreCase(command)) {
+                outputDisplayList(view, params[0]);
             } else if (REMOTE_COMMAND_INVALIDATE.equalsIgnoreCase(command)) {
                 invalidate(view, params[0]);
             } else if (REMOTE_COMMAND_REQUEST_LAYOUT.equalsIgnoreCase(command)) {
@@ -1156,6 +1159,11 @@
         }
     }
 
+    private static void outputDisplayList(View root, String parameter) throws IOException {
+        final View view = findView(root, parameter);
+        view.getViewAncestor().outputDisplayList(view);
+    }
+
     private static void capture(View root, final OutputStream clientStream, String parameter)
             throws IOException {
 
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 1a84175..35cca4f 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -536,7 +536,7 @@
                 // note: knowing that mFocused is non-null is not a good enough reason
                 // to break the traversal since in that case we'd actually have to find
                 // the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and
-                // an ancestor of v; this will get checked for at ViewRoot
+                // an ancestor of v; this will get checked for at ViewAncestor
                 && !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) {
             mParent.focusableViewAvailable(v);
         }
@@ -936,7 +936,7 @@
         final float tx = event.mX;
         final float ty = event.mY;
 
-        ViewRoot root = getViewRoot();
+        ViewAncestor root = getViewAncestor();
 
         // Dispatch down the view hierarchy
         switch (event.mAction) {
@@ -3828,13 +3828,13 @@
                     if (drawAnimation) {
                         if (view != null) {
                             view.mPrivateFlags |= DRAW_ANIMATION;
-                        } else if (parent instanceof ViewRoot) {
-                            ((ViewRoot) parent).mIsAnimating = true;
+                        } else if (parent instanceof ViewAncestor) {
+                            ((ViewAncestor) parent).mIsAnimating = true;
                         }
                     }
 
-                    if (parent instanceof ViewRoot) {
-                        ((ViewRoot) parent).invalidate();
+                    if (parent instanceof ViewAncestor) {
+                        ((ViewAncestor) parent).invalidate();
                         parent = null;
                     } else if (view != null) {
                         if ((view.mPrivateFlags & DRAWN) == DRAWN ||
@@ -3889,8 +3889,8 @@
                     if (drawAnimation) {
                         if (view != null) {
                             view.mPrivateFlags |= DRAW_ANIMATION;
-                        } else if (parent instanceof ViewRoot) {
-                            ((ViewRoot) parent).mIsAnimating = true;
+                        } else if (parent instanceof ViewAncestor) {
+                            ((ViewAncestor) parent).mIsAnimating = true;
                         }
                     }
 
@@ -4413,7 +4413,7 @@
             // If this group is dirty, check that the parent is dirty as well
             if ((mPrivateFlags & DIRTY_MASK) != 0) {
                 final ViewParent parent = getParent();
-                if (parent != null && !(parent instanceof ViewRoot)) {
+                if (parent != null && !(parent instanceof ViewAncestor)) {
                     if ((((View) parent).mPrivateFlags & DIRTY_MASK) == 0) {
                         result = false;
                         android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
@@ -4973,6 +4973,19 @@
     }
 
     /**
+     * Return true if the pressed state should be delayed for children or descendants of this
+     * ViewGroup. Generally, this should be done for containers that can scroll, such as a List.
+     * This prevents the pressed state from appearing when the user is actually trying to scroll
+     * the content.
+     *
+     * The default implementation returns true for compatibility reasons. Subclasses that do
+     * not scroll should generally override this method and return false.
+     */
+    public boolean shouldDelayChildPressedState() {
+        return true;
+    }
+
+    /**
      * LayoutParams are used by views to tell their parents how they want to be
      * laid out. See
      * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 8a18aaf..9395d5c 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -388,6 +388,12 @@
         public static final int TYPE_POINTER = FIRST_SYSTEM_WINDOW+18;
 
         /**
+         * Window type: Navigation bar (when distinct from status bar)
+         * @hide
+         */
+        public static final int TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19;
+
+        /**
          * End of types of system windows.
          */
         public static final int LAST_SYSTEM_WINDOW      = 2999;
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 8336959..d7a3096 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -111,7 +111,7 @@
         final WindowManager.LayoutParams wparams
                 = (WindowManager.LayoutParams)params;
         
-        ViewRoot root;
+        ViewAncestor root;
         View panelParentView = null;
         
         synchronized (this) {
@@ -148,7 +148,7 @@
                 }
             }
             
-            root = new ViewRoot(view.getContext());
+            root = new ViewAncestor(view.getContext());
             root.mAddNesting = 1;
 
             view.setLayoutParams(wparams);
@@ -156,7 +156,7 @@
             if (mViews == null) {
                 index = 1;
                 mViews = new View[1];
-                mRoots = new ViewRoot[1];
+                mRoots = new ViewAncestor[1];
                 mParams = new WindowManager.LayoutParams[1];
             } else {
                 index = mViews.length + 1;
@@ -164,7 +164,7 @@
                 mViews = new View[index];
                 System.arraycopy(old, 0, mViews, 0, index-1);
                 old = mRoots;
-                mRoots = new ViewRoot[index];
+                mRoots = new ViewAncestor[index];
                 System.arraycopy(old, 0, mRoots, 0, index-1);
                 old = mParams;
                 mParams = new WindowManager.LayoutParams[index];
@@ -192,7 +192,7 @@
 
         synchronized (this) {
             int index = findViewLocked(view, true);
-            ViewRoot root = mRoots[index];
+            ViewAncestor root = mRoots[index];
             mParams[index] = wparams;
             root.setLayoutParams(wparams, false);
         }
@@ -207,14 +207,14 @@
             }
             
             throw new IllegalStateException("Calling with view " + view
-                    + " but the ViewRoot is attached to " + curView);
+                    + " but the ViewAncestor is attached to " + curView);
         }
     }
 
     public void removeViewImmediate(View view) {
         synchronized (this) {
             int index = findViewLocked(view, true);
-            ViewRoot root = mRoots[index];
+            ViewAncestor root = mRoots[index];
             View curView = root.getView();
             
             root.mAddNesting = 0;
@@ -225,12 +225,12 @@
             }
             
             throw new IllegalStateException("Calling with view " + view
-                    + " but the ViewRoot is attached to " + curView);
+                    + " but the ViewAncestor is attached to " + curView);
         }
     }
     
     View removeViewLocked(int index) {
-        ViewRoot root = mRoots[index];
+        ViewAncestor root = mRoots[index];
         View view = root.getView();
         
         // Don't really remove until we have matched all calls to add().
@@ -256,7 +256,7 @@
         removeItem(tmpViews, mViews, index);
         mViews = tmpViews;
         
-        ViewRoot[] tmpRoots = new ViewRoot[count-1];
+        ViewAncestor[] tmpRoots = new ViewAncestor[count-1];
         removeItem(tmpRoots, mRoots, index);
         mRoots = tmpRoots;
         
@@ -281,7 +281,7 @@
                 //Log.i("foo", "@ " + i + " token " + mParams[i].token
                 //        + " view " + mRoots[i].getView());
                 if (token == null || mParams[i].token == token) {
-                    ViewRoot root = mRoots[i];
+                    ViewAncestor root = mRoots[i];
                     root.mAddNesting = 1;
                     
                     //Log.i("foo", "Force closing " + root);
@@ -308,7 +308,7 @@
             int count = mViews.length;
             for (int i=0; i<count; i++) {
                 if (token == null || mParams[i].token == token) {
-                    ViewRoot root = mRoots[i];
+                    ViewAncestor root = mRoots[i];
                     root.setStopped(stopped);
                 }
             }
@@ -317,13 +317,13 @@
     
     public WindowManager.LayoutParams getRootViewLayoutParameter(View view) {
         ViewParent vp = view.getParent();
-        while (vp != null && !(vp instanceof ViewRoot)) {
+        while (vp != null && !(vp instanceof ViewAncestor)) {
             vp = vp.getParent();
         }
         
         if (vp == null) return null;
         
-        ViewRoot vr = (ViewRoot)vp;
+        ViewAncestor vr = (ViewAncestor)vp;
         
         int N = mRoots.length;
         for (int i = 0; i < N; ++i) {
@@ -344,7 +344,7 @@
     }
 
     private View[] mViews;
-    private ViewRoot[] mRoots;
+    private ViewAncestor[] mRoots;
     private WindowManager.LayoutParams[] mParams;
 
     private static void removeItem(Object[] dst, Object[] src, int index)
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index dd2d00d..b4303f4 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -34,7 +34,7 @@
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.View;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
 
 class ComposingText implements NoCopySpan {
 }
@@ -501,7 +501,7 @@
                 }
             }
             if (h != null) {
-                h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
+                h.sendMessage(h.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
                         event));
             }
         }
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index eef2a33..27cbaf7 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -41,7 +41,7 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -636,7 +636,7 @@
                 if (vh != null) {
                     // This will result in a call to reportFinishInputConnection()
                     // below.
-                    vh.sendMessage(vh.obtainMessage(ViewRoot.FINISH_INPUT_CONNECTION,
+                    vh.sendMessage(vh.obtainMessage(ViewAncestor.FINISH_INPUT_CONNECTION,
                             mServedInputConnection));
                 }
             }
@@ -1093,9 +1093,9 @@
 
     void scheduleCheckFocusLocked(View view) {
         Handler vh = view.getHandler();
-        if (vh != null && !vh.hasMessages(ViewRoot.CHECK_FOCUS)) {
+        if (vh != null && !vh.hasMessages(ViewAncestor.CHECK_FOCUS)) {
             // This will result in a call to checkFocus() below.
-            vh.sendMessage(vh.obtainMessage(ViewRoot.CHECK_FOCUS));
+            vh.sendMessage(vh.obtainMessage(ViewAncestor.CHECK_FOCUS));
         }
     }
     
@@ -1150,7 +1150,7 @@
     }
     
     /**
-     * Called by ViewRoot when its window gets input focus.
+     * Called by ViewAncestor when its window gets input focus.
      * @hide
      */
     public void onWindowFocus(View rootView, View focusedView, int softInputMode,
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 6306274..9f2fd12 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -35,7 +35,7 @@
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.Surface;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
 import android.view.WindowManager;
 
 import junit.framework.Assert;
@@ -222,7 +222,7 @@
             sConfigCallback = new ConfigCallback(
                     (WindowManager) appContext.getSystemService(
                             Context.WINDOW_SERVICE));
-            ViewRoot.addConfigCallback(sConfigCallback);
+            ViewAncestor.addConfigCallback(sConfigCallback);
         }
         sConfigCallback.addHandler(this);
 
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index b5d0492..0504532 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -986,6 +986,7 @@
     protected WebView(Context context, AttributeSet attrs, int defStyle,
             Map<String, Object> javaScriptInterfaces, boolean privateBrowsing) {
         super(context, attrs, defStyle);
+        checkThread();
 
         // Used by the chrome stack to find application paths
         JniUtil.setContext(context);
@@ -1138,7 +1139,7 @@
                         PackageInfo pInfo = pm.getPackageInfo(name,
                                 PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES);
                         installedPackages.add(name);
-                    } catch(PackageManager.NameNotFoundException e) {
+                    } catch (PackageManager.NameNotFoundException e) {
                         // package not found
                     }
                 }
@@ -1193,6 +1194,11 @@
         mHTML5VideoViewProxy = null ;
     }
 
+    @Override
+    public boolean shouldDelayChildPressedState() {
+        return true;
+    }
+
     /**
      * Adds accessibility APIs to JavaScript.
      *
@@ -1309,6 +1315,7 @@
      * @param overlay TRUE if horizontal scrollbar should have overlay style.
      */
     public void setHorizontalScrollbarOverlay(boolean overlay) {
+        checkThread();
         mOverlayHorizontalScrollbar = overlay;
     }
 
@@ -1317,6 +1324,7 @@
      * @param overlay TRUE if vertical scrollbar should have overlay style.
      */
     public void setVerticalScrollbarOverlay(boolean overlay) {
+        checkThread();
         mOverlayVerticalScrollbar = overlay;
     }
 
@@ -1325,6 +1333,7 @@
      * @return TRUE if horizontal scrollbar has overlay style.
      */
     public boolean overlayHorizontalScrollbar() {
+        checkThread();
         return mOverlayHorizontalScrollbar;
     }
 
@@ -1333,6 +1342,7 @@
      * @return TRUE if vertical scrollbar has overlay style.
      */
     public boolean overlayVerticalScrollbar() {
+        checkThread();
         return mOverlayVerticalScrollbar;
     }
 
@@ -1364,6 +1374,7 @@
      * @deprecated This method is now obsolete.
      */
     public int getVisibleTitleHeight() {
+        checkThread();
         // need to restrict mScrollY due to over scroll
         return Math.max(getTitleHeight() - Math.max(0, mScrollY), 0);
     }
@@ -1390,6 +1401,7 @@
      * there is no certificate (the site is not secure).
      */
     public SslCertificate getCertificate() {
+        checkThread();
         return mCertificate;
     }
 
@@ -1397,6 +1409,7 @@
      * Sets the SSL certificate for the main top-level page.
      */
     public void setCertificate(SslCertificate certificate) {
+        checkThread();
         if (DebugFlags.WEB_VIEW) {
             Log.v(LOGTAG, "setCertificate=" + certificate);
         }
@@ -1416,6 +1429,7 @@
      * @param password The password for the given host.
      */
     public void savePassword(String host, String username, String password) {
+        checkThread();
         mDatabase.setUsernamePassword(host, username, password);
     }
 
@@ -1430,6 +1444,7 @@
      */
     public void setHttpAuthUsernamePassword(String host, String realm,
             String username, String password) {
+        checkThread();
         mDatabase.setHttpAuthUsernamePassword(host, realm, username, password);
     }
 
@@ -1443,6 +1458,7 @@
      *         String[1] is password. Return null if it can't find anything.
      */
     public String[] getHttpAuthUsernamePassword(String host, String realm) {
+        checkThread();
         return mDatabase.getHttpAuthUsernamePassword(host, realm);
     }
 
@@ -1475,6 +1491,11 @@
      * methods may be called on a WebView after destroy.
      */
     public void destroy() {
+        checkThread();
+        destroyImpl();
+    }
+
+    private void destroyImpl() {
         clearHelpers();
         if (mListBoxDialog != null) {
             mListBoxDialog.dismiss();
@@ -1511,6 +1532,7 @@
      * Enables platform notifications of data state and proxy changes.
      */
     public static void enablePlatformNotifications() {
+        checkThread();
         Network.enablePlatformNotifications();
     }
 
@@ -1519,6 +1541,7 @@
      * from the Activity's onPause() or onStop().
      */
     public static void disablePlatformNotifications() {
+        checkThread();
         Network.disablePlatformNotifications();
     }
 
@@ -1530,6 +1553,7 @@
      * @hide pending API solidification
      */
     public void setJsFlags(String flags) {
+        checkThread();
         mWebViewCore.sendMessage(EventHub.SET_JS_FLAGS, flags);
     }
 
@@ -1540,6 +1564,7 @@
      * @param networkUp boolean indicating if network is available
      */
     public void setNetworkAvailable(boolean networkUp) {
+        checkThread();
         mWebViewCore.sendMessage(EventHub.SET_NETWORK_STATE,
                 networkUp ? 1 : 0, 0);
     }
@@ -1549,6 +1574,7 @@
      * {@hide}
      */
     public void setNetworkType(String type, String subtype) {
+        checkThread();
         Map<String, String> map = new HashMap<String, String>();
         map.put("type", type);
         map.put("subtype", subtype);
@@ -1568,6 +1594,7 @@
      * @see #restorePicture
      */
     public WebBackForwardList saveState(Bundle outState) {
+        checkThread();
         if (outState == null) {
             return null;
         }
@@ -1622,6 +1649,7 @@
      * @return True if the picture was successfully saved.
      */
     public boolean savePicture(Bundle b, final File dest) {
+        checkThread();
         if (dest == null || b == null) {
             return false;
         }
@@ -1684,6 +1712,7 @@
      * @return True if the picture was successfully restored.
      */
     public boolean restorePicture(Bundle b, File src) {
+        checkThread();
         if (src == null || b == null) {
             return false;
         }
@@ -1736,6 +1765,7 @@
      * @see #restorePicture
      */
     public WebBackForwardList restoreState(Bundle inState) {
+        checkThread();
         WebBackForwardList returnList = null;
         if (inState == null) {
             return returnList;
@@ -1795,6 +1825,11 @@
      *            will be replaced by the intrinsic value of the WebView.
      */
     public void loadUrl(String url, Map<String, String> extraHeaders) {
+        checkThread();
+        loadUrlImpl(url, extraHeaders);
+    }
+
+    private void loadUrlImpl(String url, Map<String, String> extraHeaders) {
         switchOutDrawHistory();
         WebViewCore.GetUrlData arg = new WebViewCore.GetUrlData();
         arg.mUrl = url;
@@ -1808,10 +1843,15 @@
      * @param url The url of the resource to load.
      */
     public void loadUrl(String url) {
+        checkThread();
+        loadUrlImpl(url);
+    }
+
+    private void loadUrlImpl(String url) {
         if (url == null) {
             return;
         }
-        loadUrl(url, null);
+        loadUrlImpl(url, null);
     }
 
     /**
@@ -1823,6 +1863,7 @@
      * @param postData The data will be passed to "POST" request.
      */
     public void postUrl(String url, byte[] postData) {
+        checkThread();
         if (URLUtil.isNetworkUrl(url)) {
             switchOutDrawHistory();
             WebViewCore.PostUrlData arg = new WebViewCore.PostUrlData();
@@ -1831,7 +1872,7 @@
             mWebViewCore.sendMessage(EventHub.POST_URL, arg);
             clearHelpers();
         } else {
-            loadUrl(url);
+            loadUrlImpl(url);
         }
     }
 
@@ -1846,7 +1887,12 @@
      * @param encoding The encoding of the data. i.e. utf-8, base64
      */
     public void loadData(String data, String mimeType, String encoding) {
-        loadUrl("data:" + mimeType + ";" + encoding + "," + data);
+        checkThread();
+        loadDataImpl(data, mimeType, encoding);
+    }
+
+    private void loadDataImpl(String data, String mimeType, String encoding) {
+        loadUrlImpl("data:" + mimeType + ";" + encoding + "," + data);
     }
 
     /**
@@ -1872,9 +1918,10 @@
      */
     public void loadDataWithBaseURL(String baseUrl, String data,
             String mimeType, String encoding, String historyUrl) {
+        checkThread();
 
         if (baseUrl != null && baseUrl.toLowerCase().startsWith("data:")) {
-            loadData(data, mimeType, encoding);
+            loadDataImpl(data, mimeType, encoding);
             return;
         }
         switchOutDrawHistory();
@@ -1894,7 +1941,8 @@
      * @param filename The filename where the archive should be placed.
      */
     public void saveWebArchive(String filename) {
-        saveWebArchive(filename, false, null);
+        checkThread();
+        saveWebArchiveImpl(filename, false, null);
     }
 
     /* package */ static class SaveWebArchiveMessage {
@@ -1923,6 +1971,12 @@
      *                 file failed.
      */
     public void saveWebArchive(String basename, boolean autoname, ValueCallback<String> callback) {
+        checkThread();
+        saveWebArchiveImpl(basename, autoname, callback);
+    }
+
+    private void saveWebArchiveImpl(String basename, boolean autoname,
+            ValueCallback<String> callback) {
         mWebViewCore.sendMessage(EventHub.SAVE_WEBARCHIVE,
             new SaveWebArchiveMessage(basename, autoname, callback));
     }
@@ -1931,6 +1985,7 @@
      * Stop the current load.
      */
     public void stopLoading() {
+        checkThread();
         // TODO: should we clear all the messages in the queue before sending
         // STOP_LOADING?
         switchOutDrawHistory();
@@ -1941,6 +1996,7 @@
      * Reload the current url.
      */
     public void reload() {
+        checkThread();
         clearHelpers();
         switchOutDrawHistory();
         mWebViewCore.sendMessage(EventHub.RELOAD);
@@ -1951,6 +2007,7 @@
      * @return True iff this WebView has a back history item.
      */
     public boolean canGoBack() {
+        checkThread();
         WebBackForwardList l = mCallbackProxy.getBackForwardList();
         synchronized (l) {
             if (l.getClearPending()) {
@@ -1965,7 +2022,8 @@
      * Go back in the history of this WebView.
      */
     public void goBack() {
-        goBackOrForward(-1);
+        checkThread();
+        goBackOrForwardImpl(-1);
     }
 
     /**
@@ -1973,6 +2031,7 @@
      * @return True iff this Webview has a forward history item.
      */
     public boolean canGoForward() {
+        checkThread();
         WebBackForwardList l = mCallbackProxy.getBackForwardList();
         synchronized (l) {
             if (l.getClearPending()) {
@@ -1987,7 +2046,8 @@
      * Go forward in the history of this WebView.
      */
     public void goForward() {
-        goBackOrForward(1);
+        checkThread();
+        goBackOrForwardImpl(1);
     }
 
     /**
@@ -1997,6 +2057,7 @@
      *              history.
      */
     public boolean canGoBackOrForward(int steps) {
+        checkThread();
         WebBackForwardList l = mCallbackProxy.getBackForwardList();
         synchronized (l) {
             if (l.getClearPending()) {
@@ -2016,6 +2077,11 @@
      *              forward list.
      */
     public void goBackOrForward(int steps) {
+        checkThread();
+        goBackOrForwardImpl(steps);
+    }
+
+    private void goBackOrForwardImpl(int steps) {
         goBackOrForward(steps, false);
     }
 
@@ -2031,6 +2097,7 @@
      * Returns true if private browsing is enabled in this WebView.
      */
     public boolean isPrivateBrowsingEnabled() {
+        checkThread();
         return getSettings().isPrivateBrowsingEnabled();
     }
 
@@ -2053,6 +2120,7 @@
      * @return true if the page was scrolled
      */
     public boolean pageUp(boolean top) {
+        checkThread();
         if (mNativeClass == 0) {
             return false;
         }
@@ -2079,6 +2147,7 @@
      * @return true if the page was scrolled
      */
     public boolean pageDown(boolean bottom) {
+        checkThread();
         if (mNativeClass == 0) {
             return false;
         }
@@ -2103,6 +2172,7 @@
      * and onMeasure() will return 0 if MeasureSpec is not MeasureSpec.EXACTLY
      */
     public void clearView() {
+        checkThread();
         mContentWidth = 0;
         mContentHeight = 0;
         setBaseLayer(0, null, false, false);
@@ -2119,6 +2189,7 @@
      *         bounds of the view.
      */
     public Picture capturePicture() {
+        checkThread();
         if (mNativeClass == 0) return null;
         Picture result = new Picture();
         nativeCopyBaseContentToPicture(result);
@@ -2149,6 +2220,7 @@
      * @return The current scale.
      */
     public float getScale() {
+        checkThread();
         return mZoomManager.getScale();
     }
 
@@ -2161,6 +2233,7 @@
      * @param scaleInPercent The initial scale in percent.
      */
     public void setInitialScale(int scaleInPercent) {
+        checkThread();
         mZoomManager.setInitialScaleInPercent(scaleInPercent);
     }
 
@@ -2170,6 +2243,7 @@
      * level of this WebView.
      */
     public void invokeZoomPicker() {
+        checkThread();
         if (!getSettings().supportZoom()) {
             Log.w(LOGTAG, "This WebView doesn't support zoom.");
             return;
@@ -2197,6 +2271,7 @@
      * HitTestResult type is set to UNKNOWN_TYPE.
      */
     public HitTestResult getHitTestResult() {
+        checkThread();
         return hitTestResult(mInitialHitTestResult);
     }
 
@@ -2278,6 +2353,7 @@
      *                - "src" returns the image's src attribute.
      */
     public void requestFocusNodeHref(Message hrefMsg) {
+        checkThread();
         if (hrefMsg == null) {
             return;
         }
@@ -2306,6 +2382,7 @@
      *            as the data member with "url" as key. The result can be null.
      */
     public void requestImageRef(Message msg) {
+        checkThread();
         if (0 == mNativeClass) return; // client isn't initialized
         int contentX = viewToContentX(mLastTouchX + mScrollX);
         int contentY = viewToContentY(mLastTouchY + mScrollY);
@@ -2802,6 +2879,7 @@
      * @return The url for the current page.
      */
     public String getUrl() {
+        checkThread();
         WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
         return h != null ? h.getUrl() : null;
     }
@@ -2815,6 +2893,7 @@
      * @return The url that was originally requested for the current page.
      */
     public String getOriginalUrl() {
+        checkThread();
         WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
         return h != null ? h.getOriginalUrl() : null;
     }
@@ -2825,6 +2904,7 @@
      * @return The title for the current page.
      */
     public String getTitle() {
+        checkThread();
         WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
         return h != null ? h.getTitle() : null;
     }
@@ -2835,6 +2915,7 @@
      * @return The favicon for the current page.
      */
     public Bitmap getFavicon() {
+        checkThread();
         WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
         return h != null ? h.getFavicon() : null;
     }
@@ -2855,6 +2936,7 @@
      * @return The progress for the current page between 0 and 100.
      */
     public int getProgress() {
+        checkThread();
         return mCallbackProxy.getProgress();
     }
 
@@ -2862,6 +2944,7 @@
      * @return the height of the HTML content.
      */
     public int getContentHeight() {
+        checkThread();
         return mContentHeight;
     }
 
@@ -2879,6 +2962,7 @@
      * useful if the application has been paused.
      */
     public void pauseTimers() {
+        checkThread();
         mWebViewCore.sendMessage(EventHub.PAUSE_TIMERS);
     }
 
@@ -2887,6 +2971,7 @@
      * This will resume dispatching all timers.
      */
     public void resumeTimers() {
+        checkThread();
         mWebViewCore.sendMessage(EventHub.RESUME_TIMERS);
     }
 
@@ -2899,6 +2984,7 @@
      * Note that this differs from pauseTimers(), which affects all WebViews.
      */
     public void onPause() {
+        checkThread();
         if (!mIsPaused) {
             mIsPaused = true;
             mWebViewCore.sendMessage(EventHub.ON_PAUSE);
@@ -2914,6 +3000,7 @@
      * Call this to resume a WebView after a previous call to onPause().
      */
     public void onResume() {
+        checkThread();
         if (mIsPaused) {
             mIsPaused = false;
             mWebViewCore.sendMessage(EventHub.ON_RESUME);
@@ -2934,6 +3021,7 @@
      * free any available memory.
      */
     public void freeMemory() {
+        checkThread();
         mWebViewCore.sendMessage(EventHub.FREE_MEMORY);
     }
 
@@ -2944,6 +3032,7 @@
      * @param includeDiskFiles If false, only the RAM cache is cleared.
      */
     public void clearCache(boolean includeDiskFiles) {
+        checkThread();
         // Note: this really needs to be a static method as it clears cache for all
         // WebView. But we need mWebViewCore to send message to WebCore thread, so
         // we can't make this static.
@@ -2956,6 +3045,7 @@
      * currently focused textfield if there is one.
      */
     public void clearFormData() {
+        checkThread();
         if (inEditingMode()) {
             AutoCompleteAdapter adapter = null;
             mWebTextView.setAdapterCustom(adapter);
@@ -2966,6 +3056,7 @@
      * Tell the WebView to clear its internal back/forward list.
      */
     public void clearHistory() {
+        checkThread();
         mCallbackProxy.getBackForwardList().setClearPending();
         mWebViewCore.sendMessage(EventHub.CLEAR_HISTORY);
     }
@@ -2975,6 +3066,7 @@
      * certificate errors.
      */
     public void clearSslPreferences() {
+        checkThread();
         mWebViewCore.sendMessage(EventHub.CLEAR_SSL_PREF_TABLE);
     }
 
@@ -2987,6 +3079,7 @@
      * updated to reflect any new state.
      */
     public WebBackForwardList copyBackForwardList() {
+        checkThread();
         return mCallbackProxy.getBackForwardList().clone();
     }
 
@@ -2998,6 +3091,7 @@
      * @param forward Direction to search.
      */
     public void findNext(boolean forward) {
+        checkThread();
         if (0 == mNativeClass) return; // client isn't initialized
         nativeFindNext(forward);
     }
@@ -3009,6 +3103,7 @@
      *              that were found.
      */
     public int findAll(String find) {
+        checkThread();
         if (0 == mNativeClass) return 0; // client isn't initialized
         int result = find != null ? nativeFindAll(find.toLowerCase(),
                 find.toUpperCase(), find.equalsIgnoreCase(mLastFind)) : 0;
@@ -3028,6 +3123,7 @@
      * @return boolean True if the find dialog is shown, false otherwise.
      */
     public boolean showFindDialog(String text, boolean showIme) {
+        checkThread();
         FindActionModeCallback callback = new FindActionModeCallback(mContext);
         if (getParent() == null || startActionMode(callback) == null) {
             // Could not start the action mode, so end Find on page
@@ -3104,6 +3200,7 @@
      * @return the address, or if no address is found, return null.
      */
     public static String findAddress(String addr) {
+        checkThread();
         return findAddress(addr, false);
     }
 
@@ -3137,6 +3234,7 @@
      * Clear the highlighting surrounding text matches created by findAll.
      */
     public void clearMatches() {
+        checkThread();
         if (mNativeClass == 0)
             return;
         nativeSetFindIsEmpty();
@@ -3166,6 +3264,7 @@
      * @param response The message that will be dispatched with the result.
      */
     public void documentHasImages(Message response) {
+        checkThread();
         if (response == null) {
             return;
         }
@@ -3561,6 +3660,7 @@
      * @param client An implementation of WebViewClient.
      */
     public void setWebViewClient(WebViewClient client) {
+        checkThread();
         mCallbackProxy.setWebViewClient(client);
     }
 
@@ -3581,6 +3681,7 @@
      * @param listener An implementation of DownloadListener.
      */
     public void setDownloadListener(DownloadListener listener) {
+        checkThread();
         mCallbackProxy.setDownloadListener(listener);
     }
 
@@ -3591,6 +3692,7 @@
      * @param client An implementation of WebChromeClient.
      */
     public void setWebChromeClient(WebChromeClient client) {
+        checkThread();
         mCallbackProxy.setWebChromeClient(client);
     }
 
@@ -3629,6 +3731,7 @@
      * @param listener An implementation of WebView.PictureListener.
      */
     public void setPictureListener(PictureListener listener) {
+        checkThread();
         mPictureListener = listener;
     }
 
@@ -3670,6 +3773,7 @@
      *                      JavaScript.
      */
     public void addJavascriptInterface(Object obj, String interfaceName) {
+        checkThread();
         if (obj == null) {
             return;
         }
@@ -3684,6 +3788,7 @@
      * @param interfaceName The name of the interface to remove.
      */
     public void removeJavascriptInterface(String interfaceName) {
+        checkThread();
         if (mWebViewCore != null) {
             WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
             arg.mInterfaceName = interfaceName;
@@ -3698,6 +3803,7 @@
      *         settings.
      */
     public WebSettings getSettings() {
+        checkThread();
         return (mWebViewCore != null) ? mWebViewCore.getSettings() : null;
     }
 
@@ -3710,6 +3816,7 @@
     */
     @Deprecated
     public static synchronized PluginList getPluginList() {
+        checkThread();
         return new PluginList();
     }
 
@@ -3718,7 +3825,9 @@
     * @deprecated This was used for Gears, which has been deprecated.
     */
     @Deprecated
-    public void refreshPlugins(boolean reloadOpenPages) { }
+    public void refreshPlugins(boolean reloadOpenPages) {
+        checkThread();
+    }
 
     //-------------------------------------------------------------------------
     // Override View methods
@@ -3727,7 +3836,7 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            destroy();
+            destroyImpl();
         } finally {
             super.finalize();
         }
@@ -4988,6 +5097,7 @@
      * Do not rely on this functionality; it will be deprecated in the future.
      */
     public void emulateShiftHeld() {
+        checkThread();
         setUpSelect(false, 0, 0);
     }
 
@@ -6257,6 +6367,7 @@
     private boolean mMapTrackballToArrowKeys = true;
 
     public void setMapTrackballToArrowKeys(boolean setMap) {
+        checkThread();
         mMapTrackballToArrowKeys = setMap;
     }
 
@@ -6549,6 +6660,7 @@
     }
 
     public void flingScroll(int vx, int vy) {
+        checkThread();
         mScroller.fling(mScrollX, mScrollY, vx, vy, 0, computeMaxScrollX(), 0,
                 computeMaxScrollY(), mOverflingDistance, mOverflingDistance);
         invalidate();
@@ -6684,6 +6796,7 @@
      */
     @Deprecated
     public View getZoomControls() {
+        checkThread();
         if (!getSettings().supportZoom()) {
             Log.w(LOGTAG, "This WebView doesn't support zoom.");
             return null;
@@ -6703,6 +6816,7 @@
      * @return TRUE if the WebView can be zoomed in.
      */
     public boolean canZoomIn() {
+        checkThread();
         return mZoomManager.canZoomIn();
     }
 
@@ -6710,6 +6824,7 @@
      * @return TRUE if the WebView can be zoomed out.
      */
     public boolean canZoomOut() {
+        checkThread();
         return mZoomManager.canZoomOut();
     }
 
@@ -6718,6 +6833,7 @@
      * @return TRUE if zoom in succeeds. FALSE if no zoom changes.
      */
     public boolean zoomIn() {
+        checkThread();
         return mZoomManager.zoomIn();
     }
 
@@ -6726,6 +6842,7 @@
      * @return TRUE if zoom out succeeds. FALSE if no zoom changes.
      */
     public boolean zoomOut() {
+        checkThread();
         return mZoomManager.zoomOut();
     }
 
@@ -8682,6 +8799,7 @@
     }
 
     public void debugDump() {
+        checkThread();
         nativeDebugDump();
         mWebViewCore.sendMessage(EventHub.DUMP_NAVTREE);
     }
@@ -8743,6 +8861,19 @@
         return mViewManager;
     }
 
+    private static void checkThread() {
+        if (!"main".equals(Thread.currentThread().getName())) {
+            try {
+                throw new RuntimeException("A WebView method was called on thread '" +
+                        Thread.currentThread().getName() + "'. " +
+                        "All WebView methods must be called on the UI thread. " +
+                        "Future versions of WebView may not support use on other threads.");
+            } catch (RuntimeException e) {
+                Log.e(LOGTAG, Log.getStackTraceString(e));
+            }
+        }
+    }
+
     private native int nativeCacheHitFramePointer();
     private native boolean  nativeCacheHitIsPlugin();
     private native Rect nativeCacheHitNodeBounds();
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index d63d421..df4c4ed 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2818,7 +2818,7 @@
                         if (ev.getEdgeFlags() != 0 && motionPosition < 0) {
                             // If we couldn't find a view to click on, but the down event
                             // was touching the edge, we will bail out and try again.
-                            // This allows the edge correcting code in ViewRoot to try to
+                            // This allows the edge correcting code in ViewAncestor to try to
                             // find a nearby view to select
                             return false;
                         }
@@ -5021,7 +5021,7 @@
                     public boolean sendKeyEvent(KeyEvent event) {
                         // Use our own input connection, since the filter
                         // text view may not be shown in a window so has
-                        // no ViewRoot to dispatch events with.
+                        // no ViewAncestor to dispatch events with.
                         return mDefInputConnection.sendKeyEvent(event);
                     }
                 };
diff --git a/core/java/android/widget/AbsoluteLayout.java b/core/java/android/widget/AbsoluteLayout.java
index ac82af7..7df6aab 100644
--- a/core/java/android/widget/AbsoluteLayout.java
+++ b/core/java/android/widget/AbsoluteLayout.java
@@ -141,6 +141,11 @@
         return new LayoutParams(p);
     }
 
+    @Override
+    public boolean shouldDelayChildPressedState() {
+        return false;
+    }
+
     /**
      * Per-child layout information associated with AbsoluteLayout.
      * See
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 590a768..0659063 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -485,6 +485,11 @@
         return new FrameLayout.LayoutParams(getContext(), attrs);        
     }
 
+    @Override
+    public boolean shouldDelayChildPressedState() {
+        return false;
+    }
+
     /**
      * {@inheritDoc}
      */
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index dbe9288..86fefaf 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -201,6 +201,11 @@
         mShowDividers = showDividers;
     }
 
+    @Override
+    public boolean shouldDelayChildPressedState() {
+        return false;
+    }
+
     /**
      * @return A flag set indicating how dividers should be shown around items.
      * @see #setShowDividers(int)
@@ -254,6 +259,15 @@
         return mDividerPadding;
     }
 
+    /**
+     * Get the width of the current divider drawable.
+     *
+     * @hide Used internally by framework.
+     */
+    public int getDividerWidth() {
+        return mDividerWidth;
+    }
+
     @Override
     protected void onDraw(Canvas canvas) {
         if (mDivider == null) {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index d115364..e11f5bb 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1568,7 +1568,7 @@
 
             // take focus back to us temporarily to avoid the eventual
             // call to clear focus when removing the focused child below
-            // from messing things up when ViewRoot assigns focus back
+            // from messing things up when ViewAncestor assigns focus back
             // to someone else
             final View focusedChild = getFocusedChild();
             if (focusedChild != null) {
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index a47359f..9069283 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -186,6 +186,11 @@
         a.recycle();
     }
 
+    @Override
+    public boolean shouldDelayChildPressedState() {
+        return false;
+    }
+
     /**
      * Defines which View is ignored when the gravity is applied. This setting has no
      * effect if the gravity is <code>Gravity.LEFT | Gravity.TOP</code>.
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 4b4f5f2..27edb88 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -162,6 +162,11 @@
     }
 
     @Override
+    public boolean shouldDelayChildPressedState() {
+        return true;
+    }
+
+    @Override
     protected float getTopFadingEdgeStrength() {
         if (getChildCount() == 0) {
             return 0.0f;
@@ -873,7 +878,7 @@
             int count = getChildCount();
             if (count > 0) {
                 View view = getChildAt(count - 1);
-                mTempRect.bottom = view.getBottom();
+                mTempRect.bottom = view.getBottom() + mPaddingBottom;
                 mTempRect.top = mTempRect.bottom - height;
             }
         }
@@ -949,9 +954,7 @@
             } else if (direction == View.FOCUS_DOWN) {
                 if (getChildCount() > 0) {
                     int daBottom = getChildAt(0).getBottom();
-
-                    int screenBottom = getScrollY() + getHeight();
-
+                    int screenBottom = getScrollY() + getHeight() - mPaddingBottom;
                     if (daBottom - screenBottom < maxJump) {
                         scrollDelta = daBottom - screenBottom;
                     }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 6430b43..86b6b1d 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -113,7 +113,7 @@
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewParent;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
@@ -3373,13 +3373,13 @@
         Handler h = getHandler();
         if (h != null) {
             long eventTime = SystemClock.uptimeMillis();
-            h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
+            h.sendMessage(h.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
                     new KeyEvent(eventTime, eventTime,
                     KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0, 0,
                     KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
                     KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
                     | KeyEvent.FLAG_EDITOR_ACTION)));
-            h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
+            h.sendMessage(h.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
                     new KeyEvent(SystemClock.uptimeMillis(), eventTime,
                     KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0, 0,
                     KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
@@ -7152,7 +7152,7 @@
                 }
 
                 // The DecorView does not have focus when the 'Done' ExtractEditText button is
-                // pressed. Since it is the ViewRoot's mView, it requests focus before
+                // pressed. Since it is the ViewAncestor's mView, it requests focus before
                 // ExtractEditText clears focus, which gives focus to the ExtractEditText.
                 // This special case ensure that we keep current selection in that case.
                 // It would be better to know why the DecorView does not have focus at that time.
@@ -8302,7 +8302,7 @@
                     suggestionInfo.spanEnd = spanEnd;
 
                     totalNbSuggestions++;
-                    if (totalNbSuggestions > MAX_NUMBER_SUGGESTIONS) {
+                    if (totalNbSuggestions == MAX_NUMBER_SUGGESTIONS) {
                         // Also end outer for loop
                         spanIndex = nbSpans;
                         break;
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index 450c966..9e37c7b 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -33,7 +33,7 @@
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewParent;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
 import android.view.WindowManager;
 import android.view.View.OnClickListener;
 import android.view.WindowManager.LayoutParams;
@@ -501,7 +501,7 @@
 
         } else {
 
-            ViewRoot viewRoot = getOwnerViewRoot();
+            ViewAncestor viewRoot = getOwnerViewAncestor();
             if (viewRoot != null) {
                 viewRoot.dispatchKey(event);
             }
@@ -526,15 +526,15 @@
         }
     }
 
-    private ViewRoot getOwnerViewRoot() {
+    private ViewAncestor getOwnerViewAncestor() {
         View rootViewOfOwner = mOwnerView.getRootView();
         if (rootViewOfOwner == null) {
             return null;
         }
 
         ViewParent parentOfRootView = rootViewOfOwner.getParent();
-        if (parentOfRootView instanceof ViewRoot) {
-            return (ViewRoot) parentOfRootView;
+        if (parentOfRootView instanceof ViewAncestor) {
+            return (ViewAncestor) parentOfRootView;
         } else {
             return null;
         }
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 57df259..1e576ce 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -19,6 +19,7 @@
 import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.view.menu.MenuPopupHelper;
 import com.android.internal.view.menu.SubMenuBuilder;
+import com.android.internal.widget.AbsActionBarView;
 import com.android.internal.widget.ActionBarContainer;
 import com.android.internal.widget.ActionBarContextView;
 import com.android.internal.widget.ActionBarView;
@@ -46,7 +47,6 @@
 import android.view.Window;
 import android.view.animation.DecelerateInterpolator;
 import android.widget.HorizontalScrollView;
-import android.widget.LinearLayout;
 import android.widget.SpinnerAdapter;
 
 import java.lang.ref.WeakReference;
@@ -61,8 +61,6 @@
  */
 public class ActionBarImpl extends ActionBar {
     private static final String TAG = "ActionBarImpl";
-    private static final int NORMAL_VIEW = 0;
-    private static final int CONTEXT_VIEW = 1;
 
     private Context mContext;
     private Activity mActivity;
@@ -70,8 +68,8 @@
 
     private ActionBarContainer mContainerView;
     private ActionBarView mActionView;
-    private ActionBarContextView mUpperContextView;
-    private LinearLayout mLowerView;
+    private ActionBarContextView mContextView;
+    private ActionBarContainer mSplitView;
     private View mContentView;
     private ViewGroup mExternalTabView;
 
@@ -102,26 +100,6 @@
 
     private static final TimeInterpolator sFadeOutInterpolator = new DecelerateInterpolator();
 
-    final AnimatorListener[] mAfterAnimation = new AnimatorListener[] {
-            new AnimatorListenerAdapter() { // NORMAL_VIEW
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    if (mLowerView != null) {
-                        mLowerView.removeAllViews();
-                    }
-                    mCurrentModeAnim = null;
-                    hideAllExcept(NORMAL_VIEW);
-                }
-            },
-            new AnimatorListenerAdapter() { // CONTEXT_VIEW
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mCurrentModeAnim = null;
-                    hideAllExcept(CONTEXT_VIEW);
-                }
-            }
-    };
-
     final AnimatorListener mHideListener = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
@@ -160,19 +138,19 @@
     private void init(View decor) {
         mContext = decor.getContext();
         mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
-        mUpperContextView = (ActionBarContextView) decor.findViewById(
+        mContextView = (ActionBarContextView) decor.findViewById(
                 com.android.internal.R.id.action_context_bar);
-        mLowerView = (LinearLayout) decor.findViewById(
-                com.android.internal.R.id.lower_action_context_bar);
         mContainerView = (ActionBarContainer) decor.findViewById(
                 com.android.internal.R.id.action_bar_container);
+        mSplitView = (ActionBarContainer) decor.findViewById(
+                com.android.internal.R.id.split_action_bar);
 
-        if (mActionView == null || mUpperContextView == null || mContainerView == null) {
+        if (mActionView == null || mContextView == null || mContainerView == null) {
             throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
                     "with a compatible window decor layout");
         }
 
-        mActionView.setContextView(mUpperContextView);
+        mActionView.setContextView(mContextView);
         mContextDisplayMode = mActionView.isSplitActionBar() ?
                 CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
 
@@ -341,16 +319,16 @@
             mActionMode.finish();
         }
 
-        mUpperContextView.killMode();
+        mContextView.killMode();
         ActionMode mode = new ActionModeImpl(callback);
         if (callback.onCreateActionMode(mode, mode.getMenu())) {
             mWasHiddenBeforeMode = !isShowing();
             mode.invalidate();
-            mUpperContextView.initForMode(mode);
-            animateTo(CONTEXT_VIEW);
-            if (mLowerView != null) {
+            mContextView.initForMode(mode);
+            animateToMode(true);
+            if (mSplitView != null) {
                 // TODO animate this
-                mLowerView.setVisibility(View.VISIBLE);
+                mSplitView.setVisibility(View.VISIBLE);
             }
             mActionMode = mode;
             return mode;
@@ -418,7 +396,10 @@
         int selectedTabPosition = mSelectedTab != null
                 ? mSelectedTab.getPosition() : mSavedTabPosition;
         mActionView.removeTabAt(position);
-        mTabs.remove(position);
+        TabImpl removedTab = mTabs.remove(position);
+        if (removedTab != null) {
+            removedTab.setPosition(-1);
+        }
 
         final int newTabCount = mTabs.size();
         for (int i = position; i < newTabCount; i++) {
@@ -495,6 +476,10 @@
                 mContainerView.setTranslationY(-mContainerView.getHeight());
                 b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 0));
             }
+            if (mSplitView != null) {
+                mSplitView.setAlpha(0);
+                b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 1));
+            }
             anim.addListener(mShowListener);
             mCurrentShowAnim = anim;
             anim.start();
@@ -525,6 +510,10 @@
                 b.with(ObjectAnimator.ofFloat(mContainerView, "translationY",
                         -mContainerView.getHeight()));
             }
+            if (mSplitView != null) {
+                mSplitView.setAlpha(1);
+                b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 0));
+            }
             anim.addListener(mHideListener);
             mCurrentShowAnim = anim;
             anim.start();
@@ -537,45 +526,14 @@
         return mContainerView.getVisibility() == View.VISIBLE;
     }
 
-    long animateTo(int viewIndex) {
+    void animateToMode(boolean toActionMode) {
         show(false);
         if (mCurrentModeAnim != null) {
             mCurrentModeAnim.end();
         }
 
-        AnimatorSet set = new AnimatorSet();
-
-        final View targetChild = mContainerView.getChildAt(viewIndex);
-        targetChild.setVisibility(View.VISIBLE);
-        targetChild.setAlpha(0);
-        AnimatorSet.Builder b = set.play(ObjectAnimator.ofFloat(targetChild, "alpha", 1));
-
-        final int count = mContainerView.getChildCount();
-        for (int i = 0; i < count; i++) {
-            final View child = mContainerView.getChildAt(i);
-            if (i == viewIndex || child == mContainerView.getTabContainer()) {
-                continue;
-            }
-
-            if (child.getVisibility() != View.GONE) {
-                Animator a = ObjectAnimator.ofFloat(child, "alpha", 0);
-                a.setInterpolator(sFadeOutInterpolator);
-                b.with(a);
-            }
-        }
-
-        set.addListener(mAfterAnimation[viewIndex]);
-
-        mCurrentModeAnim = set;
-        set.start();
-        return set.getDuration();
-    }
-
-    private void hideAllExcept(int viewIndex) {
-        final int count = mContainerView.getChildCount();
-        for (int i = 0; i < count; i++) {
-            mContainerView.getChildAt(i).setVisibility(i == viewIndex ? View.VISIBLE : View.GONE);
-        }
+        mActionView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
+        mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE);
     }
 
     /**
@@ -612,14 +570,10 @@
 
             mCallback.onDestroyActionMode(this);
             mCallback = null;
-            animateTo(NORMAL_VIEW);
+            animateToMode(false);
 
             // Clear out the context mode views after the animation finishes
-            mUpperContextView.closeMode();
-            if (mLowerView != null && mLowerView.getVisibility() != View.GONE) {
-                // TODO Animate this
-                mLowerView.setVisibility(View.GONE);
-            }
+            mContextView.closeMode();
             mActionMode = null;
 
             if (mWasHiddenBeforeMode) {
@@ -636,18 +590,18 @@
 
         @Override
         public void setCustomView(View view) {
-            mUpperContextView.setCustomView(view);
+            mContextView.setCustomView(view);
             mCustomView = new WeakReference<View>(view);
         }
 
         @Override
         public void setSubtitle(CharSequence subtitle) {
-            mUpperContextView.setSubtitle(subtitle);
+            mContextView.setSubtitle(subtitle);
         }
 
         @Override
         public void setTitle(CharSequence title) {
-            mUpperContextView.setTitle(title);
+            mContextView.setTitle(title);
         }
 
         @Override
@@ -662,12 +616,12 @@
 
         @Override
         public CharSequence getTitle() {
-            return mUpperContextView.getTitle();
+            return mContextView.getTitle();
         }
 
         @Override
         public CharSequence getSubtitle() {
-            return mUpperContextView.getSubtitle();
+            return mContextView.getSubtitle();
         }
         
         @Override
@@ -707,7 +661,7 @@
                 return;
             }
             invalidate();
-            mUpperContextView.showOverflowMenu();
+            mContextView.showOverflowMenu();
         }
     }
 
@@ -719,7 +673,7 @@
         private Object mTag;
         private Drawable mIcon;
         private CharSequence mText;
-        private int mPosition;
+        private int mPosition = -1;
         private View mCustomView;
 
         @Override
@@ -751,6 +705,7 @@
         @Override
         public Tab setCustomView(View view) {
             mCustomView = view;
+            if (mPosition >= 0) mActionView.updateTab(mPosition);
             return this;
         }
 
@@ -781,6 +736,7 @@
         @Override
         public Tab setIcon(Drawable icon) {
             mIcon = icon;
+            if (mPosition >= 0) mActionView.updateTab(mPosition);
             return this;
         }
 
@@ -792,6 +748,7 @@
         @Override
         public Tab setText(CharSequence text) {
             mText = text;
+            if (mPosition >= 0) mActionView.updateTab(mPosition);
             return this;
         }
 
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 7cf33fc..12687a1 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -4904,7 +4904,7 @@
     void readOldHistory(Parcel in) {
         mHistory = mHistoryEnd = mHistoryCache = null;
         long time;
-        while ((time=in.readLong()) >= 0) {
+        while (in.dataAvail() > 0 && (time=in.readLong()) >= 0) {
             HistoryItem rec = new HistoryItem(time, in);
             addHistoryRecordLocked(rec);
         }
diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java
index 4d656c0c..3973344 100644
--- a/core/java/com/android/internal/util/AsyncChannel.java
+++ b/core/java/com/android/internal/util/AsyncChannel.java
@@ -44,16 +44,16 @@
  * In this usage model there is no need for the destination to
  * use the connect methods. The typical sequence of operations is:</p>
  *<ol>
- *   <li>Client calls AsyncChannel#connect</li>
- *   <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
+ *   <li>Client calls AsyncChannel#connectSync or Asynchronously:</li>
+ *      <ol>For an asynchronous half connection client calls AsyncChannel#connect.</ol>
+ *          <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
+ *      </ol>
  *   <li><code>comm-loop:</code></li>
- *   <li>Client calls AsyncChannel#sendMessage(msgX)</li>
- *   <li>Server receives and processes msgX</li>
- *   <li>Server optionally calls AsyncChannel#replyToMessage(msgY)
- *       and if sent Client receives and processes msgY</li>
+ *   <li>Client calls AsyncChannel#sendMessage</li>
+ *   <li>Server processes messages and optionally replies using AsyncChannel#replyToMessage
  *   <li>Loop to <code>comm-loop</code> until done</li>
- *   <li>When done Client calls {@link AsyncChannel#disconnect(int)}</li>
- *   <li>Client receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li>
+ *   <li>When done Client calls {@link AsyncChannel#disconnect}</li>
+ *   <li>Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li>
  *</ol>
  *<br/>
  * <p>A second usage model is where the server/destination needs to know
@@ -62,21 +62,26 @@
  * different state for each client. In this model the server will also
  * use the connect methods. The typical sequence of operation is:</p>
  *<ol>
- *   <li>Client calls AsyncChannel#connect</li>
- *   <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
- *   <li>Client calls AsyncChannel#sendMessage(CMD_CHANNEL_FULL_CONNECTION)</li>
+ *   <li>Client calls AsyncChannel#fullyConnectSync or Asynchronously:<li>
+ *      <ol>For an asynchronous full connection it calls AsyncChannel#connect</li>
+ *          <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
+ *          <li>Client calls AsyncChannel#sendMessage(CMD_CHANNEL_FULL_CONNECTION)</li>
+ *      </ol>
  *   <li>Server receives CMD_CHANNEL_FULL_CONNECTION</li>
- *   <li>Server calls AsyncChannel#connect</li>
- *   <li>Server receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
+ *   <li>Server calls AsyncChannel#connected</li>
  *   <li>Server sends AsyncChannel#sendMessage(CMD_CHANNEL_FULLY_CONNECTED)</li>
  *   <li>Client receives CMD_CHANNEL_FULLY_CONNECTED</li>
  *   <li><code>comm-loop:</code></li>
  *   <li>Client/Server uses AsyncChannel#sendMessage/replyToMessage
  *       to communicate and perform work</li>
  *   <li>Loop to <code>comm-loop</code> until done</li>
- *   <li>When done Client/Server calls {@link AsyncChannel#disconnect(int)}</li>
+ *   <li>When done Client/Server calls {@link AsyncChannel#disconnect}</li>
  *   <li>Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li>
  *</ol>
+ *
+ * TODO: Consider simplifying where we have connect and fullyConnect with only one response
+ * message RSP_CHANNEL_CONNECT instead of two, CMD_CHANNEL_HALF_CONNECTED and
+ * CMD_CHANNEL_FULLY_CONNECTED. We'd also change CMD_CHANNEL_FULL_CONNECTION to REQ_CHANNEL_CONNECT.
  */
 public class AsyncChannel {
     /** Log tag */
@@ -85,6 +90,8 @@
     /** Enable to turn on debugging */
     private static final boolean DBG = false;
 
+    private static final int BASE = Protocol.BASE_SYSTEM_ASYNC_CHANNEL;
+
     /**
      * Command sent when the channel is half connected. Half connected
      * means that the channel can be used to send commends to the destination
@@ -98,7 +105,7 @@
      * msg.obj  == the AsyncChannel
      * msg.replyTo == dstMessenger if successful
      */
-    public static final int CMD_CHANNEL_HALF_CONNECTED = -1;
+    public static final int CMD_CHANNEL_HALF_CONNECTED = BASE + 0;
 
     /**
      * Command typically sent when after receiving the CMD_CHANNEL_HALF_CONNECTED.
@@ -107,7 +114,7 @@
      *
      * msg.replyTo = srcMessenger.
      */
-    public static final int CMD_CHANNEL_FULL_CONNECTION = -2;
+    public static final int CMD_CHANNEL_FULL_CONNECTION = BASE + 1;
 
     /**
      * Command typically sent after the destination receives a CMD_CHANNEL_FULL_CONNECTION.
@@ -115,20 +122,20 @@
      *
      * msg.arg1 == 0 : Accept connection
      *               : All other values signify the destination rejected the connection
-     *                 and {@link AsyncChannel#disconnect(int)} would typically be called.
+     *                 and {@link AsyncChannel#disconnect} would typically be called.
      */
-    public static final int CMD_CHANNEL_FULLY_CONNECTED = -3;
+    public static final int CMD_CHANNEL_FULLY_CONNECTED = BASE + 2;
 
     /**
      * Command sent when one side or the other wishes to disconnect. The sender
      * may or may not be able to receive a reply depending upon the protocol and
-     * the state of the connection. The receiver should call {@link AsyncChannel#disconnect(int)}
+     * the state of the connection. The receiver should call {@link AsyncChannel#disconnect}
      * to close its side of the channel and it will receive a CMD_CHANNEL_DISCONNECTED
      * when the channel is closed.
      *
      * msg.replyTo = messenger that is disconnecting
      */
-    public static final int CMD_CHANNEL_DISCONNECT = -4;
+    public static final int CMD_CHANNEL_DISCONNECT = BASE + 3;
 
     /**
      * Command sent when the channel becomes disconnected. This is sent when the
@@ -141,7 +148,7 @@
      * msg.obj  == the AsyncChannel
      * msg.replyTo = messenger disconnecting or null if it was never connected.
      */
-    public static final int CMD_CHANNEL_DISCONNECTED = -5;
+    public static final int CMD_CHANNEL_DISCONNECTED = BASE + 4;
 
     /** Successful status always 0, !0 is an unsuccessful status */
     public static final int STATUS_SUCCESSFUL = 0;
@@ -152,6 +159,9 @@
     /** Error attempting to send a message */
     public static final int STATUS_SEND_UNSUCCESSFUL = 2;
 
+    /** CMD_FULLY_CONNECTED refused because a connection already exists*/
+    public static final int STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED = 3;
+
     /** Service connection */
     private AsyncChannelConnection mConnection;
 
@@ -174,9 +184,7 @@
     }
 
     /**
-     * Connect handler to named package/class.
-     *
-     * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete.
+     * Connect handler to named package/class synchronously.
      *
      * @param srcContext is the context of the source
      * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
@@ -184,8 +192,10 @@
      * @param dstPackageName is the destination package name
      * @param dstClassName is the fully qualified class name (i.e. contains
      *            package name)
+     *
+     * @return STATUS_SUCCESSFUL on success any other value is an error.
      */
-    private void connectSrcHandlerToPackage(
+    public int connectSrcHandlerToPackageSync(
             Context srcContext, Handler srcHandler, String dstPackageName, String dstClassName) {
         if (DBG) log("connect srcHandler to dst Package & class E");
 
@@ -207,11 +217,61 @@
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.setClassName(dstPackageName, dstClassName);
         boolean result = srcContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
-        if (!result) {
-            replyHalfConnected(STATUS_BINDING_UNSUCCESSFUL);
-        }
-
         if (DBG) log("connect srcHandler to dst Package & class X result=" + result);
+        return result ? STATUS_SUCCESSFUL : STATUS_BINDING_UNSUCCESSFUL;
+    }
+
+    /**
+     * Connect a handler to Messenger synchronously.
+     *
+     * @param srcContext is the context of the source
+     * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
+     *            messages
+     * @param dstMessenger is the hander to send messages to.
+     *
+     * @return STATUS_SUCCESSFUL on success any other value is an error.
+     */
+    public int connectSync(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
+        if (DBG) log("halfConnectSync srcHandler to the dstMessenger  E");
+
+        // We are connected
+        connected(srcContext, srcHandler, dstMessenger);
+
+        if (DBG) log("halfConnectSync srcHandler to the dstMessenger X");
+        return STATUS_SUCCESSFUL;
+    }
+
+    /**
+     * connect two local Handlers synchronously.
+     *
+     * @param srcContext is the context of the source
+     * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
+     *            messages
+     * @param dstHandler is the hander to send messages to.
+     *
+     * @return STATUS_SUCCESSFUL on success any other value is an error.
+     */
+    public int connectSync(Context srcContext, Handler srcHandler, Handler dstHandler) {
+        return connectSync(srcContext, srcHandler, new Messenger(dstHandler));
+    }
+
+    /**
+     * Fully connect two local Handlers synchronously.
+     *
+     * @param srcContext is the context of the source
+     * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
+     *            messages
+     * @param dstHandler is the hander to send messages to.
+     *
+     * @return STATUS_SUCCESSFUL on success any other value is an error.
+     */
+    public int fullyConnectSync(Context srcContext, Handler srcHandler, Handler dstHandler) {
+        int status = connectSync(srcContext, srcHandler, dstHandler);
+        if (status == STATUS_SUCCESSFUL) {
+            Message response = sendMessageSynchronously(CMD_CHANNEL_FULL_CONNECTION);
+            status = response.arg1;
+        }
+        return status;
     }
 
     /**
@@ -246,8 +306,11 @@
                 mDstClassName = dstClassName;
             }
 
+            @Override
             public void run() {
-                connectSrcHandlerToPackage(mSrcCtx, mSrcHdlr, mDstPackageName, mDstClassName);
+                int result = connectSrcHandlerToPackageSync(mSrcCtx, mSrcHdlr, mDstPackageName,
+                        mDstClassName);
+                replyHalfConnected(result);
             }
         }
 
@@ -286,15 +349,8 @@
     public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
         if (DBG) log("connect srcHandler to the dstMessenger  E");
 
-        // Initialize source fields
-        mSrcContext = srcContext;
-        mSrcHandler = srcHandler;
-        mSrcMessenger = new Messenger(mSrcHandler);
-
-        // Initialize destination fields
-        mDstMessenger = dstMessenger;
-
-        if (DBG) log("tell source we are half connected");
+        // We are connected
+        connected(srcContext, srcHandler, dstMessenger);
 
         // Tell source we are half connected
         replyHalfConnected(STATUS_SUCCESSFUL);
@@ -303,11 +359,31 @@
     }
 
     /**
-     * Connect two local Handlers.
+     * Connect handler to messenger. This method is typically called
+     * when a server receives a CMD_CHANNEL_FULL_CONNECTION request
+     * and initializes the internal instance variables to allow communication
+     * with the dstMessenger.
      *
-     * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete.
-     *      msg.arg1 = status
-     *      msg.obj = the AsyncChannel
+     * @param srcContext
+     * @param srcHandler
+     * @param dstMessenger
+     */
+    public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
+        if (DBG) log("connected srcHandler to the dstMessenger  E");
+
+        // Initialize source fields
+        mSrcContext = srcContext;
+        mSrcHandler = srcHandler;
+        mSrcMessenger = new Messenger(mSrcHandler);
+
+        // Initialize destination fields
+        mDstMessenger = dstMessenger;
+
+        if (DBG) log("connected srcHandler to the dstMessenger X");
+    }
+
+    /**
+     * Connect two local Handlers.
      *
      * @param srcContext is the context of the source
      * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
@@ -336,6 +412,7 @@
      * To close the connection call when handler receives CMD_CHANNEL_DISCONNECTED
      */
     public void disconnected() {
+        mSrcContext = null;
         mSrcHandler = null;
         mSrcMessenger = null;
         mDstMessenger = null;
@@ -346,7 +423,7 @@
      * Disconnect
      */
     public void disconnect() {
-        if (mConnection != null) {
+        if ((mConnection != null) && (mSrcContext != null)) {
             mSrcContext.unbindService(mConnection);
         }
         if (mSrcHandler != null) {
@@ -445,6 +522,7 @@
      */
     public void replyToMessage(Message srcMsg, Message dstMsg) {
         try {
+            dstMsg.replyTo = mSrcMessenger;
             srcMsg.replyTo.send(dstMsg);
         } catch (RemoteException e) {
             log("TODO: handle replyToMessage RemoteException" + e);
@@ -695,10 +773,14 @@
         private static Message sendMessageSynchronously(Messenger dstMessenger, Message msg) {
             SyncMessenger sm = SyncMessenger.obtain();
             try {
-                msg.replyTo = sm.mMessenger;
-                dstMessenger.send(msg);
-                synchronized (sm.mHandler.mLockObject) {
-                    sm.mHandler.mLockObject.wait();
+                if (dstMessenger != null && msg != null) {
+                    msg.replyTo = sm.mMessenger;
+                    synchronized (sm.mHandler.mLockObject) {
+                        dstMessenger.send(msg);
+                        sm.mHandler.mLockObject.wait();
+                    }
+                } else {
+                    sm.mHandler.mResultMsg = null;
                 }
             } catch (InterruptedException e) {
                 sm.mHandler.mResultMsg = null;
@@ -747,11 +829,13 @@
         AsyncChannelConnection() {
         }
 
+        @Override
         public void onServiceConnected(ComponentName className, IBinder service) {
             mDstMessenger = new Messenger(service);
             replyHalfConnected(STATUS_SUCCESSFUL);
         }
 
+        @Override
         public void onServiceDisconnected(ComponentName className) {
             replyDisconnected(STATUS_SUCCESSFUL);
         }
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index 2689f09..2e7ec58 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -29,9 +29,18 @@
  * {@hide}
  */
 public class Protocol {
-    public static final int MAX_MESSAGE     =  0x0000FFFF;
+    public static final int MAX_MESSAGE                                             = 0x0000FFFF;
 
-    public static final int BASE_WIFI       =  0x00010000;
-    public static final int BASE_DHCP       =  0x00020000;
+    /** Base reserved for system */
+    public static final int BASE_SYSTEM_RESERVED                                    = 0x00010000;
+    public static final int BASE_SYSTEM_ASYNC_CHANNEL                               = 0x00011000;
+
+    /** Non system protocols */
+    public static final int BASE_WIFI                                               = 0x00020000;
+    public static final int BASE_DHCP                                               = 0x00030000;
+    public static final int BASE_DATA_CONNECTION                                    = 0x00040000;
+    public static final int BASE_DATA_CONNECTION_AC                                 = 0x00041000;
+    public static final int BASE_DATA_CONNECTION_TRACKER                            = 0x00050000;
+
     //TODO: define all used protocols
 }
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index e210b78..0051ec3 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.util.Log;
 import android.util.SparseBooleanArray;
 import android.view.MenuItem;
 import android.view.SoundEffectConstants;
@@ -36,11 +35,14 @@
  * MenuPresenter for building action menus as seen in the action bar and action modes.
  */
 public class ActionMenuPresenter extends BaseMenuPresenter {
+    private static final String TAG = "ActionMenuPresenter";
+
     private View mOverflowButton;
     private boolean mReserveOverflow;
     private int mWidthLimit;
     private int mActionItemWidthLimit;
     private int mMaxItems;
+    private boolean mStrictWidthLimit;
 
     // Group IDs that have been added as actions - used temporarily, allocated here for reuse.
     private final SparseBooleanArray mActionButtonGroups = new SparseBooleanArray();
@@ -89,11 +91,12 @@
         mScrapActionButtonView = null;
     }
 
-    public void setWidthLimit(int width) {
+    public void setWidthLimit(int width, boolean strict) {
         if (mReserveOverflow) {
             width -= mOverflowButton.getMeasuredWidth();
         }
         mActionItemWidthLimit = width;
+        mStrictWidthLimit = strict;
     }
 
     public void setItemLimit(int itemCount) {
@@ -131,6 +134,8 @@
         if (mReserveOverflow && mMenu.getNonActionItems().size() > 0) {
             if (mOverflowButton == null) {
                 mOverflowButton = new OverflowMenuButton(mContext);
+                mOverflowButton.setLayoutParams(
+                        ((ActionMenuView) mMenuView).generateOverflowButtonLayoutParams());
             }
             ViewGroup parent = (ViewGroup) mOverflowButton.getParent();
             if (parent != mMenuView) {
@@ -189,7 +194,6 @@
     public boolean showOverflowMenu() {
         if (mReserveOverflow && !isOverflowMenuShowing() && mMenuView != null &&
                 mPostedOpenRunnable == null) {
-            Log.d("ActionMenuPresenter", "showOverflowMenu");
             OverflowPopup popup = new OverflowPopup(mContext, mMenu, mOverflowButton, true);
             mPostedOpenRunnable = new OpenOverflowRunnable(popup);
             // Post this for later; we might still need a layout for the anchor to be right.
@@ -338,9 +342,11 @@
                         firstActionWidth = measuredWidth;
                     }
 
-                    // Did this push the entire first item past halfway?
-                    if (widthLimit + firstActionWidth <= 0) {
-                        isAction = false;
+                    if (mStrictWidthLimit) {
+                        isAction = widthLimit >= 0;
+                    } else {
+                        // Did this push the entire first item past the limit?
+                        isAction = widthLimit + firstActionWidth > 0;
                     }
                 }
 
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index 0ea9c89..290bf08 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -20,6 +20,7 @@
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.View;
+import android.view.ViewDebug;
 import android.view.ViewGroup;
 import android.widget.LinearLayout;
 
@@ -33,6 +34,8 @@
 
     private boolean mReserveOverflow;
     private ActionMenuPresenter mPresenter;
+    private boolean mUpdateContentsBeforeMeasure;
+    private boolean mFormatItems;
 
     public ActionMenuView(Context context) {
         this(context, null);
@@ -59,6 +62,95 @@
     }
 
     @Override
+    public void requestLayout() {
+        // Layout can influence how many action items fit.
+        mUpdateContentsBeforeMeasure = true;
+        super.requestLayout();
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (mUpdateContentsBeforeMeasure && mMenu != null) {
+            mMenu.onItemsChanged(true);
+            mUpdateContentsBeforeMeasure = false;
+        }
+        // If we've been given an exact size to match, apply special formatting during layout.
+        mFormatItems = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY;
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        if (!mFormatItems) {
+            super.onLayout(changed, left, top, right, bottom);
+            return;
+        }
+
+        final int childCount = getChildCount();
+        final int midVertical = (top + bottom) / 2;
+        final int dividerWidth = getDividerWidth();
+        boolean hasOverflow = false;
+        int overflowWidth = 0;
+        int nonOverflowWidth = 0;
+        int nonOverflowCount = 0;
+        int widthRemaining = right - left - getPaddingRight() - getPaddingLeft();
+        for (int i = 0; i < childCount; i++) {
+            final View v = getChildAt(i);
+            if (v.getVisibility() == GONE) {
+                continue;
+            }
+
+            LayoutParams p = (LayoutParams) v.getLayoutParams();
+            if (p.isOverflowButton) {
+                hasOverflow = true;
+                overflowWidth = v.getMeasuredWidth();
+                if (hasDividerBeforeChildAt(i)) {
+                    overflowWidth += dividerWidth;
+                }
+
+                int height = v.getMeasuredHeight();
+                int r = getPaddingRight();
+                int l = r - overflowWidth;
+                int t = midVertical - (height / 2);
+                int b = t + height;
+                v.layout(l, t, r, b);
+
+                widthRemaining -= overflowWidth;
+            } else {
+                nonOverflowWidth += v.getMeasuredWidth() + p.leftMargin + p.rightMargin;
+                if (hasDividerBeforeChildAt(i)) {
+                    nonOverflowWidth += dividerWidth;
+                }
+                nonOverflowCount++;
+            }
+        }
+
+        // Try to center non-overflow items with uniformly spaced padding, including on the edges.
+        // Overflow will always pin to the right edge. If there isn't enough room for that,
+        // center in the remaining space.
+        if (nonOverflowWidth <= widthRemaining - overflowWidth) {
+            widthRemaining -= overflowWidth;
+        }
+
+        final int spacing = (widthRemaining - nonOverflowWidth) / (nonOverflowCount + 1);
+        int startLeft = getPaddingLeft() + overflowWidth + spacing;
+        for (int i = 0; i < childCount; i++) {
+            final View v = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) v.getLayoutParams();
+            if (v.getVisibility() == GONE || lp.isOverflowButton) {
+                continue;
+            }
+
+            startLeft += lp.leftMargin;
+            int width = v.getMeasuredWidth();
+            int height = v.getMeasuredHeight();
+            int t = midVertical - (height / 2);
+            v.layout(startLeft, t, startLeft + width, t + height);
+            startLeft += width + lp.rightMargin + spacing;
+        }
+    }
+
+    @Override
     public void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         mPresenter.dismissPopupMenus();
@@ -97,6 +189,12 @@
         return p instanceof LayoutParams;
     }
 
+    public LayoutParams generateOverflowButtonLayoutParams() {
+        LayoutParams result = generateDefaultLayoutParams();
+        result.isOverflowButton = true;
+        return result;
+    }
+
     public boolean invokeItem(MenuItemImpl item) {
         return mMenu.performItemAction(item, 0);
     }
@@ -127,4 +225,28 @@
         public boolean needsDividerBefore();
         public boolean needsDividerAfter();
     }
+
+    public static class LayoutParams extends LinearLayout.LayoutParams {
+        @ViewDebug.ExportedProperty(category = "layout")
+        public boolean isOverflowButton;
+
+        public LayoutParams(Context c, AttributeSet attrs) {
+            super(c, attrs);
+        }
+
+        public LayoutParams(LayoutParams other) {
+            super((LinearLayout.LayoutParams) other);
+            isOverflowButton = other.isOverflowButton;
+        }
+
+        public LayoutParams(int width, int height) {
+            super(width, height);
+            isOverflowButton = false;
+        }
+
+        public LayoutParams(int width, int height, boolean isOverflowButton) {
+            super(width, height);
+            this.isOverflowButton = isOverflowButton;
+        }
+    }
 }
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 7fba5ca..e9fcb23 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -226,6 +226,7 @@
     private void dispatchPresenterUpdate(boolean cleared) {
         if (mPresenters.isEmpty()) return;
 
+        stopDispatchingItemsChanged();
         for (WeakReference<MenuPresenter> ref : mPresenters) {
             final MenuPresenter presenter = ref.get();
             if (presenter == null) {
@@ -234,6 +235,7 @@
                 presenter.updateMenuView(cleared);
             }
         }
+        startDispatchingItemsChanged();
     }
     
     private boolean dispatchSubMenuSelected(SubMenuBuilder subMenu) {
diff --git a/core/java/com/android/internal/view/menu/MenuDialogHelper.java b/core/java/com/android/internal/view/menu/MenuDialogHelper.java
index 6387c9b..5c8e057 100644
--- a/core/java/com/android/internal/view/menu/MenuDialogHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuDialogHelper.java
@@ -37,6 +37,7 @@
     private MenuBuilder mMenu;
     private AlertDialog mDialog;
     ListMenuPresenter mPresenter;
+    private MenuPresenter.Callback mPresenterCallback;
     
     public MenuDialogHelper(MenuBuilder menu) {
         mMenu = menu;
@@ -124,6 +125,10 @@
 
     }
 
+    public void setPresenterCallback(MenuPresenter.Callback cb) {
+        mPresenterCallback = cb;
+    }
+
     /**
      * Dismisses the menu's dialog.
      * 
@@ -145,10 +150,16 @@
         if (allMenusAreClosing || menu == mMenu) {
             dismiss();
         }
+        if (mPresenterCallback != null) {
+            mPresenterCallback.onCloseMenu(menu, allMenusAreClosing);
+        }
     }
 
     @Override
     public boolean onOpenSubMenu(MenuBuilder subMenu) {
+        if (mPresenterCallback != null) {
+            return mPresenterCallback.onOpenSubMenu(subMenu);
+        }
         return false;
     }
 
diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java
new file mode 100644
index 0000000..7830dca
--- /dev/null
+++ b/core/java/com/android/internal/widget/AbsActionBarView.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget;
+
+import com.android.internal.view.menu.ActionMenuPresenter;
+import com.android.internal.view.menu.ActionMenuView;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.DecelerateInterpolator;
+
+public abstract class AbsActionBarView extends ViewGroup {
+    protected ActionMenuView mMenuView;
+    protected ActionMenuPresenter mMenuPresenter;
+    protected ActionBarContainer mSplitView;
+
+    protected Animator mVisibilityAnim;
+    protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener();
+
+    private static final TimeInterpolator sAlphaInterpolator = new DecelerateInterpolator();
+
+    private static final int FADE_DURATION = 200;
+
+    public AbsActionBarView(Context context) {
+        super(context);
+    }
+
+    public AbsActionBarView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public AbsActionBarView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    public void setSplitView(ActionBarContainer splitView) {
+        mSplitView = splitView;
+    }
+
+    public void animateToVisibility(int visibility) {
+        if (mVisibilityAnim != null) {
+            mVisibilityAnim.cancel();
+        }
+        if (visibility == VISIBLE) {
+            if (getVisibility() != VISIBLE) {
+                setAlpha(0);
+                if (mSplitView != null && mMenuView != null) {
+                    mMenuView.setAlpha(0);
+                }
+            }
+            ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 1);
+            anim.setDuration(FADE_DURATION);
+            anim.setInterpolator(sAlphaInterpolator);
+            if (mSplitView != null && mMenuView != null) {
+                AnimatorSet set = new AnimatorSet();
+                ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 1);
+                splitAnim.setDuration(FADE_DURATION);
+                set.addListener(mVisAnimListener.withFinalVisibility(visibility));
+                set.play(anim).with(splitAnim);
+                set.start();
+            } else {
+                anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
+                anim.start();
+            }
+        } else {
+            ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 0);
+            anim.setDuration(FADE_DURATION);
+            anim.setInterpolator(sAlphaInterpolator);
+            if (mSplitView != null && mMenuView != null) {
+                AnimatorSet set = new AnimatorSet();
+                ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 0);
+                splitAnim.setDuration(FADE_DURATION);
+                set.addListener(mVisAnimListener.withFinalVisibility(visibility));
+                set.play(anim).with(splitAnim);
+                set.start();
+            } else {
+                anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
+                anim.start();
+            }
+        }
+    }
+
+    @Override
+    public void setVisibility(int visibility) {
+        if (mVisibilityAnim != null) {
+            mVisibilityAnim.end();
+        }
+        super.setVisibility(visibility);
+    }
+
+    public boolean showOverflowMenu() {
+        if (mMenuPresenter != null) {
+            return mMenuPresenter.showOverflowMenu();
+        }
+        return false;
+    }
+
+    public void postShowOverflowMenu() {
+        post(new Runnable() {
+            public void run() {
+                showOverflowMenu();
+            }
+        });
+    }
+
+    public boolean hideOverflowMenu() {
+        if (mMenuPresenter != null) {
+            return mMenuPresenter.hideOverflowMenu();
+        }
+        return false;
+    }
+
+    public boolean isOverflowMenuShowing() {
+        if (mMenuPresenter != null) {
+            return mMenuPresenter.isOverflowMenuShowing();
+        }
+        return false;
+    }
+
+    public boolean isOverflowReserved() {
+        return mMenuPresenter != null && mMenuPresenter.isOverflowReserved();
+    }
+
+    public void dismissPopupMenus() {
+        if (mMenuPresenter != null) {
+            mMenuPresenter.dismissPopupMenus();
+        }
+    }
+
+    protected int measureChildView(View child, int availableWidth, int childSpecHeight,
+            int spacing) {
+        child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
+                childSpecHeight);
+
+        availableWidth -= child.getMeasuredWidth();
+        availableWidth -= spacing;
+
+        return availableWidth;
+    }
+
+    protected int positionChild(View child, int x, int y, int contentHeight) {
+        int childWidth = child.getMeasuredWidth();
+        int childHeight = child.getMeasuredHeight();
+        int childTop = y + (contentHeight - childHeight) / 2;
+
+        child.layout(x, childTop, x + childWidth, childTop + childHeight);
+
+        return childWidth;
+    }
+
+    protected int positionChildInverse(View child, int x, int y, int contentHeight) {
+        int childWidth = child.getMeasuredWidth();
+        int childHeight = child.getMeasuredHeight();
+        int childTop = y + (contentHeight - childHeight) / 2;
+
+        child.layout(x - childWidth, childTop, x, childTop + childHeight);
+
+        return childWidth;
+    }
+
+    protected class VisibilityAnimListener implements Animator.AnimatorListener {
+        private boolean mCanceled = false;
+        private int mFinalVisibility;
+
+        public VisibilityAnimListener withFinalVisibility(int visibility) {
+            mFinalVisibility = visibility;
+            return this;
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+            setVisibility(VISIBLE);
+            mVisibilityAnim = animation;
+            mCanceled = false;
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            if (mCanceled) return;
+
+            mVisibilityAnim = null;
+            setVisibility(mFinalVisibility);
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mCanceled = true;
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+        }
+    }
+}
diff --git a/core/java/com/android/internal/widget/ActionBarContainer.java b/core/java/com/android/internal/widget/ActionBarContainer.java
index 3deb036..c18565d 100644
--- a/core/java/com/android/internal/widget/ActionBarContainer.java
+++ b/core/java/com/android/internal/widget/ActionBarContainer.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
+import android.view.ActionMode;
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.FrameLayout;
@@ -85,6 +86,12 @@
     }
 
     @Override
+    public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
+        // No starting an action mode for an action bar child! (Where would it go?)
+        return null;
+    }
+
+    @Override
     public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
         if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 70fb3b2..c82323e 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -30,7 +30,7 @@
 import android.view.ActionMode;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
 import android.view.animation.DecelerateInterpolator;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -38,7 +38,7 @@
 /**
  * @hide
  */
-public class ActionBarContextView extends ViewGroup implements AnimatorListener {
+public class ActionBarContextView extends AbsActionBarView implements AnimatorListener {
     private static final String TAG = "ActionBarContextView";
 
     private int mContentHeight;
@@ -53,8 +53,6 @@
     private TextView mSubtitleView;
     private int mTitleStyleRes;
     private int mSubtitleStyleRes;
-    private ActionMenuView mMenuView;
-    private ActionMenuPresenter mPresenter;
 
     private Animator mCurrentAnimation;
     private boolean mAnimateInOnLayout;
@@ -87,12 +85,6 @@
                 com.android.internal.R.styleable.ActionMode_height, 0);
         a.recycle();
     }
-    
-    @Override
-    public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
-        // No starting an action mode for an existing action mode UI child! (Where would it go?)
-        return null;
-    }
 
     public void setHeight(int height) {
         mContentHeight = height;
@@ -178,10 +170,25 @@
         });
 
         final MenuBuilder menu = (MenuBuilder) mode.getMenu();
-        mPresenter = new ActionMenuPresenter();
-        menu.addMenuPresenter(mPresenter);
-        mMenuView = (ActionMenuView) mPresenter.getMenuView(this);
-        addView(mMenuView);
+        mMenuPresenter = new ActionMenuPresenter();
+        menu.addMenuPresenter(mMenuPresenter);
+        mMenuView = (ActionMenuView) mMenuPresenter.getMenuView(this);
+
+        final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
+                LayoutParams.MATCH_PARENT);
+        mMenuView.setLayoutParams(layoutParams);
+        if (mSplitView == null) {
+            addView(mMenuView);
+        } else {
+            // Allow full screen width in split mode.
+            mMenuPresenter.setWidthLimit(
+                    getContext().getResources().getDisplayMetrics().widthPixels, true);
+            // No limit to the item count; use whatever will fit.
+            mMenuPresenter.setItemLimit(Integer.MAX_VALUE);
+            // Span the whole width
+            layoutParams.width = LayoutParams.MATCH_PARENT;
+            mSplitView.addView(mMenuView);
+        }
 
         mAnimateInOnLayout = true;
     }
@@ -213,28 +220,31 @@
     public void killMode() {
         finishAnimation();
         removeAllViews();
+        if (mSplitView != null) {
+            mSplitView.removeView(mMenuView);
+        }
         mCustomView = null;
         mMenuView = null;
         mAnimateInOnLayout = false;
     }
 
     public boolean showOverflowMenu() {
-        if (mPresenter != null) {
-            return mPresenter.showOverflowMenu();
+        if (mMenuPresenter != null) {
+            return mMenuPresenter.showOverflowMenu();
         }
         return false;
     }
 
     public boolean hideOverflowMenu() {
-        if (mPresenter != null) {
-            return mPresenter.hideOverflowMenu();
+        if (mMenuPresenter != null) {
+            return mMenuPresenter.hideOverflowMenu();
         }
         return false;
     }
 
     public boolean isOverflowMenuShowing() {
-        if (mPresenter != null) {
-            return mPresenter.isOverflowMenuShowing();
+        if (mMenuPresenter != null) {
+            return mMenuPresenter.isOverflowMenuShowing();
         }
         return false;
     }
@@ -342,7 +352,7 @@
 
     private Animator makeOutAnimation() {
         ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX",
-                0, -mClose.getWidth());
+                -mClose.getWidth());
         buttonAnimator.setDuration(200);
         buttonAnimator.addListener(this);
         buttonAnimator.setInterpolator(new DecelerateInterpolator());
@@ -356,7 +366,7 @@
                 for (int i = 0; i < 0; i++) {
                     View child = mMenuView.getChildAt(i);
                     child.setScaleY(0);
-                    ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 1, 0);
+                    ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0);
                     a.setDuration(100);
                     a.setStartDelay(i * 70);
                     b.with(a);
@@ -383,7 +393,7 @@
                 mAnimateInOnLayout = false;
             }
         }
-        
+
         if (mTitleLayout != null && mCustomView == null) {
             x += positionChild(mTitleLayout, x, y, contentHeight);
         }
@@ -399,36 +409,6 @@
         }
     }
 
-    private int measureChildView(View child, int availableWidth, int childSpecHeight, int spacing) {
-        child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
-                childSpecHeight);
-
-        availableWidth -= child.getMeasuredWidth();
-        availableWidth -= spacing;
-
-        return availableWidth;
-    }
-    
-    private int positionChild(View child, int x, int y, int contentHeight) {
-        int childWidth = child.getMeasuredWidth();
-        int childHeight = child.getMeasuredHeight();
-        int childTop = y + (contentHeight - childHeight) / 2;
-
-        child.layout(x, childTop, x + childWidth, childTop + childHeight);
-
-        return childWidth;
-    }
-    
-    private int positionChildInverse(View child, int x, int y, int contentHeight) {
-        int childWidth = child.getMeasuredWidth();
-        int childHeight = child.getMeasuredHeight();
-        int childTop = y + (contentHeight - childHeight) / 2;
-
-        child.layout(x - childWidth, childTop, x, childTop + childHeight);
-
-        return childWidth;
-    }
-
     @Override
     public void onAnimationStart(Animator animation) {
     }
@@ -448,4 +428,9 @@
     @Override
     public void onAnimationRepeat(Animator animation) {
     }
+
+    @Override
+    public boolean shouldDelayChildPressedState() {
+        return false;
+    }
 }
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 0c13f7b..13ccbba 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -38,7 +38,6 @@
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.Log;
-import android.view.ActionMode;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -59,7 +58,7 @@
 /**
  * @hide
  */
-public class ActionBarView extends ViewGroup {
+public class ActionBarView extends AbsActionBarView {
     private static final String TAG = "ActionBarView";
 
     /**
@@ -115,11 +114,8 @@
     private boolean mIncludeTabs;
 
     private MenuBuilder mOptionsMenu;
-    private ActionMenuView mMenuView;
-    private ActionMenuPresenter mActionMenuPresenter;
     
     private ActionBarContextView mContextView;
-    private ViewGroup mSplitView;
 
     private ActionMenuItem mLogoNavItem;
 
@@ -232,6 +228,11 @@
         mHomeLayout.setFocusable(true);
     }
 
+    @Override
+    public boolean shouldDelayChildPressedState() {
+        return false;
+    }
+
     public void initProgress() {
         mProgressView = new ProgressBar(mContext, null, 0, mProgressStyle);
         mProgressView.setId(R.id.progress_horizontal);
@@ -274,12 +275,6 @@
         mTabLayout = tabLayout;
     }
 
-    @Override
-    public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
-        // No starting an action mode for an action bar child! (Where would it go?)
-        return null;
-    }
-
     public void setCallback(OnNavigationListener callback) {
         mCallback = callback;
     }
@@ -288,7 +283,7 @@
         if (menu == mOptionsMenu) return;
 
         if (mOptionsMenu != null) {
-            mOptionsMenu.removeMenuPresenter(mActionMenuPresenter);
+            mOptionsMenu.removeMenuPresenter(mMenuPresenter);
         }
 
         MenuBuilder builder = (MenuBuilder) menu;
@@ -296,12 +291,12 @@
         if (mMenuView != null) {
             removeView(mMenuView);
         }
-        if (mActionMenuPresenter == null) {
-            mActionMenuPresenter = new ActionMenuPresenter();
-            mActionMenuPresenter.setCallback(cb);
-            builder.addMenuPresenter(mActionMenuPresenter);
+        if (mMenuPresenter == null) {
+            mMenuPresenter = new ActionMenuPresenter();
+            mMenuPresenter.setCallback(cb);
+            builder.addMenuPresenter(mMenuPresenter);
         }
-        final ActionMenuView menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
+        final ActionMenuView menuView = (ActionMenuView) mMenuPresenter.getMenuView(this);
         final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
                 LayoutParams.MATCH_PARENT);
         menuView.setLayoutParams(layoutParams);
@@ -309,10 +304,12 @@
             addView(menuView);
         } else {
             // Allow full screen width in split mode.
-            mActionMenuPresenter.setWidthLimit(
-                    getContext().getResources().getDisplayMetrics().widthPixels);
+            mMenuPresenter.setWidthLimit(
+                    getContext().getResources().getDisplayMetrics().widthPixels, true);
             // No limit to the item count; use whatever will fit.
-            mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
+            mMenuPresenter.setItemLimit(Integer.MAX_VALUE);
+            // Span the whole width
+            layoutParams.width = LayoutParams.MATCH_PARENT;
             if (mSplitView != null) {
                 mSplitView.addView(menuView);
             } // We'll add this later if we missed it this time.
@@ -320,59 +317,6 @@
         mMenuView = menuView;
     }
 
-    public void setSplitView(ViewGroup splitView) {
-        mSplitView = splitView;
-        splitView.setVisibility(VISIBLE);
-        if (mMenuView != null) {
-            splitView.addView(mMenuView);
-        }
-    }
-
-    public boolean showOverflowMenu() {
-        if (mActionMenuPresenter != null) {
-            return mActionMenuPresenter.showOverflowMenu();
-        }
-        return false;
-    }
-
-    public void openOverflowMenu() {
-        if (mActionMenuPresenter != null) {
-            showOverflowMenu();
-        }
-    }
-
-    public void postShowOverflowMenu() {
-        post(new Runnable() {
-            public void run() {
-                showOverflowMenu();
-            }
-        });
-    }
-
-    public boolean hideOverflowMenu() {
-        if (mActionMenuPresenter != null) {
-            return mActionMenuPresenter.hideOverflowMenu();
-        }
-        return false;
-    }
-
-    public boolean isOverflowMenuShowing() {
-        if (mActionMenuPresenter != null) {
-            return mActionMenuPresenter.isOverflowMenuShowing();
-        }
-        return false;
-    }
-
-    public boolean isOverflowReserved() {
-        return mActionMenuPresenter != null && mActionMenuPresenter.isOverflowReserved();
-    }
-
-    public void dismissPopupMenus() {
-        if (mActionMenuPresenter != null) {
-            mActionMenuPresenter.dismissPopupMenus();
-        }
-    }
-
     public void setCustomNavigationView(View view) {
         final boolean showCustom = (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0;
         if (mCustomNavView != null && showCustom) {
@@ -451,8 +395,8 @@
             mHomeLayout.setVisibility(vis);
 
             if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
-                mHomeAsUpView.setVisibility((options & ActionBar.DISPLAY_HOME_AS_UP) != 0
-                        ? VISIBLE : GONE);
+                final boolean isUp = (options & ActionBar.DISPLAY_HOME_AS_UP) != 0;
+                mHomeAsUpView.setVisibility(isUp ? VISIBLE : GONE);
             }
 
             if ((flagsChanged & ActionBar.DISPLAY_USE_LOGO) != 0) {
@@ -480,6 +424,17 @@
         } else {
             invalidate();
         }
+
+        // Make sure the home button has an accurate content description for accessibility.
+        if ((options & ActionBar.DISPLAY_DISABLE_HOME) != 0) {
+            mHomeLayout.setContentDescription(null);
+        } else if ((options & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+            mHomeLayout.setContentDescription(mContext.getResources().getText(
+                    R.string.action_bar_up_description));
+        } else {
+            mHomeLayout.setContentDescription(mContext.getResources().getText(
+                    R.string.action_bar_home_description));
+        }
     }
 
     public void setIcon(Drawable icon) {
@@ -648,6 +603,10 @@
         }
     }
 
+    public void updateTab(int position) {
+        ((TabView) mTabLayout.getChildAt(position)).update();
+    }
+
     public void removeTabAt(int position) {
         if (mTabLayout != null) {
             mTabLayout.removeViewAt(position);
@@ -876,16 +835,6 @@
         }
     }
 
-    private int measureChildView(View child, int availableWidth, int childSpecHeight, int spacing) {
-        child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
-                childSpecHeight);
-
-        availableWidth -= child.getMeasuredWidth();
-        availableWidth -= spacing;
-
-        return availableWidth;
-    }
-
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         int x = getPaddingLeft();
@@ -998,68 +947,78 @@
         }
     }
 
-    private int positionChild(View child, int x, int y, int contentHeight) {
-        int childWidth = child.getMeasuredWidth();
-        int childHeight = child.getMeasuredHeight();
-        int childTop = y + (contentHeight - childHeight) / 2;
-
-        child.layout(x, childTop, x + childWidth, childTop + childHeight);
-
-        return childWidth;
-    }
-    
-    private int positionChildInverse(View child, int x, int y, int contentHeight) {
-        int childWidth = child.getMeasuredWidth();
-        int childHeight = child.getMeasuredHeight();
-        int childTop = y + (contentHeight - childHeight) / 2;
-
-        child.layout(x - childWidth, childTop, x, childTop + childHeight);
-
-        return childWidth;
-    }
-
     private static class TabView extends LinearLayout {
         private ActionBar.Tab mTab;
+        private TextView mTextView;
+        private ImageView mIconView;
+        private View mCustomView;
 
         public TabView(Context context, ActionBar.Tab tab) {
             super(context, null, com.android.internal.R.attr.actionBarTabStyle);
             mTab = tab;
 
+            update();
+
+            setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                    LayoutParams.MATCH_PARENT, 1));
+        }
+
+        public void update() {
+            final ActionBar.Tab tab = mTab;
             final View custom = tab.getCustomView();
             if (custom != null) {
                 addView(custom);
+                mCustomView = custom;
+                if (mTextView != null) mTextView.setVisibility(GONE);
+                if (mIconView != null) {
+                    mIconView.setVisibility(GONE);
+                    mIconView.setImageDrawable(null);
+                }
             } else {
-                // TODO Style tabs based on the theme
+                if (mCustomView != null) {
+                    removeView(mCustomView);
+                    mCustomView = null;
+                }
 
                 final Drawable icon = tab.getIcon();
                 final CharSequence text = tab.getText();
 
                 if (icon != null) {
-                    ImageView iconView = new ImageView(context);
-                    iconView.setImageDrawable(icon);
-                    LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
-                            LayoutParams.WRAP_CONTENT);
-                    lp.gravity = Gravity.CENTER_VERTICAL;
-                    iconView.setLayoutParams(lp);
-                    addView(iconView);
+                    if (mIconView == null) {
+                        ImageView iconView = new ImageView(getContext());
+                        LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
+                                LayoutParams.WRAP_CONTENT);
+                        lp.gravity = Gravity.CENTER_VERTICAL;
+                        iconView.setLayoutParams(lp);
+                        addView(iconView, 0);
+                        mIconView = iconView;
+                    }
+                    mIconView.setImageDrawable(icon);
+                    mIconView.setVisibility(VISIBLE);
+                } else if (mIconView != null) {
+                    mIconView.setVisibility(GONE);
+                    mIconView.setImageDrawable(null);
                 }
 
                 if (text != null) {
-                    TextView textView = new TextView(context, null,
-                            com.android.internal.R.attr.actionBarTabTextStyle);
-                    textView.setText(text);
-                    textView.setSingleLine();
-                    textView.setEllipsize(TruncateAt.END);
-                    LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
-                            LayoutParams.WRAP_CONTENT);
-                    lp.gravity = Gravity.CENTER_VERTICAL;
-                    textView.setLayoutParams(lp);
-                    addView(textView);
+                    if (mTextView == null) {
+                        TextView textView = new TextView(getContext(), null,
+                                com.android.internal.R.attr.actionBarTabTextStyle);
+                        textView.setSingleLine();
+                        textView.setEllipsize(TruncateAt.END);
+                        LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
+                                LayoutParams.WRAP_CONTENT);
+                        lp.gravity = Gravity.CENTER_VERTICAL;
+                        textView.setLayoutParams(lp);
+                        addView(textView);
+                        mTextView = textView;
+                    }
+                    mTextView.setText(text);
+                    mTextView.setVisibility(VISIBLE);
+                } else {
+                    mTextView.setVisibility(GONE);
                 }
             }
-
-            setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
-                    LayoutParams.MATCH_PARENT, 1));
         }
 
         public ActionBar.Tab getTab() {
diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
index 65973b6..3070e3e 100644
--- a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
+++ b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
@@ -29,7 +29,7 @@
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.View;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
 import com.android.internal.R;
 
 public class PasswordEntryKeyboardHelper implements OnKeyboardActionListener {
@@ -150,7 +150,7 @@
                 KeyEvent event = events[i];
                 event = KeyEvent.changeFlags(event, event.getFlags()
                         | KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE);
-                handler.sendMessage(handler.obtainMessage(ViewRoot.DISPATCH_KEY, event));
+                handler.sendMessage(handler.obtainMessage(ViewAncestor.DISPATCH_KEY, event));
             }
         }
     }
@@ -158,11 +158,11 @@
     public void sendDownUpKeyEvents(int keyEventCode) {
         long eventTime = SystemClock.uptimeMillis();
         Handler handler = mTargetView.getHandler();
-        handler.sendMessage(handler.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
+        handler.sendMessage(handler.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
                 new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyEventCode, 0, 0,
                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
                     KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)));
-        handler.sendMessage(handler.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
+        handler.sendMessage(handler.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
                 new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyEventCode, 0, 0,
                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
                         KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)));
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 290f528..8beb94b 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -47,7 +47,8 @@
 	android_emoji_EmojiFactory.cpp \
 	android_view_Display.cpp \
 	android_view_Surface.cpp \
-	android_view_ViewRoot.cpp \
+	android_view_TextureView.cpp \
+	android_view_ViewAncestor.cpp \
 	android_view_InputChannel.cpp \
 	android_view_InputQueue.cpp \
 	android_view_KeyEvent.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index a4a229a..17f9246 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -118,7 +118,8 @@
 extern int register_android_view_Display(JNIEnv* env);
 extern int register_android_view_GLES20Canvas(JNIEnv* env);
 extern int register_android_view_Surface(JNIEnv* env);
-extern int register_android_view_ViewRoot(JNIEnv* env);
+extern int register_android_view_TextureView(JNIEnv* env);
+extern int register_android_view_ViewAncestor(JNIEnv* env);
 extern int register_android_database_CursorWindow(JNIEnv* env);
 extern int register_android_database_SQLiteCompiledSql(JNIEnv* env);
 extern int register_android_database_SQLiteDatabase(JNIEnv* env);
@@ -1122,7 +1123,8 @@
     REG_JNI(register_android_graphics_Graphics),
     REG_JNI(register_android_view_GLES20Canvas),
     REG_JNI(register_android_view_Surface),
-    REG_JNI(register_android_view_ViewRoot),
+    REG_JNI(register_android_view_TextureView),
+    REG_JNI(register_android_view_ViewAncestor),
     REG_JNI(register_com_google_android_gles_jni_EGLImpl),
     REG_JNI(register_com_google_android_gles_jni_GLImpl),
     REG_JNI(register_android_opengl_jni_GLES10),
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index c112423..c1acaa3 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -112,6 +112,10 @@
     return create_jmovie(env, moov);
 }
 
+static void movie_destructor(JNIEnv* env, jobject, SkMovie* movie) {
+    delete movie;
+}
+
 //////////////////////////////////////////////////////////////////////////////////////////////
 
 #include <android_runtime/AndroidRuntime.h>
@@ -126,6 +130,7 @@
                             (void*)movie_draw  },
     { "decodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
                             (void*)movie_decodeStream },
+    { "nativeDestructor","(I)V", (void*)movie_destructor },
     { "decodeByteArray", "([BII)Landroid/graphics/Movie;",
                             (void*)movie_decodeByteArray },
 };
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 97580f54..4687ee0 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -218,7 +218,7 @@
 
                         if (mCallbackBuffers.isEmpty()) {
                             LOGV("Out of buffers, clearing callback!");
-                            mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
+                            mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP);
                             mManualCameraCallbackSet = false;
 
                             if (obj == NULL) {
@@ -305,22 +305,22 @@
     mManualCameraCallbackSet = false;
 
     // In order to limit the over usage of binder threads, all non-manual buffer
-    // callbacks use FRAME_CALLBACK_FLAG_BARCODE_SCANNER mode now.
+    // callbacks use CAMERA_FRAME_CALLBACK_FLAG_BARCODE_SCANNER mode now.
     //
     // Continuous callbacks will have the callback re-registered from handleMessage.
     // Manual buffer mode will operate as fast as possible, relying on the finite supply
     // of buffers for throttling.
 
     if (!installed) {
-        mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
+        mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP);
         clearCallbackBuffers_l(env, &mCallbackBuffers);
     } else if (mManualBufferMode) {
         if (!mCallbackBuffers.isEmpty()) {
-            mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA);
+            mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_CAMERA);
             mManualCameraCallbackSet = true;
         }
     } else {
-        mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_BARCODE_SCANNER);
+        mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_BARCODE_SCANNER);
         clearCallbackBuffers_l(env, &mCallbackBuffers);
     }
 }
@@ -343,7 +343,7 @@
                 // next frame. This may have come unset had we not had a
                 // callbackbuffer ready for it last time.
                 if (mManualBufferMode && !mManualCameraCallbackSet) {
-                    mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA);
+                    mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_CAMERA);
                     mManualCameraCallbackSet = true;
                 }
                 break;
@@ -456,7 +456,7 @@
 
         // clear callbacks
         if (camera != NULL) {
-            camera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
+            camera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP);
             camera->disconnect();
         }
 
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 4a0e68e..548376d 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -40,6 +40,16 @@
                     const char *dns2,
                     const char *server,
                     uint32_t  *lease);
+
+int dhcp_do_request_renew(const char *ifname,
+                    const char *ipaddr,
+                    const char *gateway,
+                    uint32_t  *prefixLength,
+                    const char *dns1,
+                    const char *dns2,
+                    const char *server,
+                    uint32_t  *lease);
+
 int dhcp_stop(const char *ifname);
 int dhcp_release_lease(const char *ifname);
 char *dhcp_get_errmsg();
@@ -57,7 +67,6 @@
 static struct fieldIds {
     jmethodID constructorId;
     jfieldID ipaddress;
-    jfieldID gateway;
     jfieldID prefixLength;
     jfieldID dns1;
     jfieldID dns2;
@@ -145,7 +154,8 @@
     return (jint)result;
 }
 
-static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstring ifname,
+        jobject info, bool renew)
 {
     int result;
     char  ipaddr[PROPERTY_VALUE_MAX];
@@ -159,12 +169,41 @@
     const char *nameStr = env->GetStringUTFChars(ifname, NULL);
     if (nameStr == NULL) return (jboolean)false;
 
-    result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
-                                        dns1, dns2, server, &lease);
+    if (renew) {
+        result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength,
+                dns1, dns2, server, &lease);
+    } else {
+        result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
+                dns1, dns2, server, &lease);
+    }
+
     env->ReleaseStringUTFChars(ifname, nameStr);
     if (result == 0) {
         env->SetObjectField(info, dhcpInfoInternalFieldIds.ipaddress, env->NewStringUTF(ipaddr));
-        env->SetObjectField(info, dhcpInfoInternalFieldIds.gateway, env->NewStringUTF(gateway));
+
+        // set the gateway
+        jclass cls = env->FindClass("java/net/InetAddress");
+        jmethodID method = env->GetStaticMethodID(cls, "getByName",
+                "(Ljava/lang/String;)Ljava/net/InetAddress;");
+        jvalue args[1];
+        args[0].l = env->NewStringUTF(gateway);
+        jobject inetAddressObject = env->CallStaticObjectMethodA(cls, method, args);
+
+        if (!env->ExceptionOccurred()) {
+            cls = env->FindClass("android/net/RouteInfo");
+            method = env->GetMethodID(cls, "<init>", "(Ljava/net/InetAddress;)V");
+            args[0].l = inetAddressObject;
+            jobject routeInfoObject = env->NewObjectA(cls, method, args);
+
+            cls = env->FindClass("android/net/DhcpInfoInternal");
+            method = env->GetMethodID(cls, "addRoute", "(Landroid/net/RouteInfo;)V");
+            args[0].l = routeInfoObject;
+            env->CallVoidMethodA(info, method, args);
+        } else {
+            // if we have an exception (host not found perhaps), just don't add the route
+            env->ExceptionClear();
+        }
+
         env->SetIntField(info, dhcpInfoInternalFieldIds.prefixLength, prefixLength);
         env->SetObjectField(info, dhcpInfoInternalFieldIds.dns1, env->NewStringUTF(dns1));
         env->SetObjectField(info, dhcpInfoInternalFieldIds.dns2, env->NewStringUTF(dns2));
@@ -175,6 +214,17 @@
     return (jboolean)(result == 0);
 }
 
+static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+{
+    return android_net_utils_runDhcpCommon(env, clazz, ifname, info, false);
+}
+
+static jboolean android_net_utils_runDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+{
+    return android_net_utils_runDhcpCommon(env, clazz, ifname, info, true);
+}
+
+
 static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname)
 {
     int result;
@@ -218,6 +268,7 @@
     { "removeDefaultRoute", "(Ljava/lang/String;)I",  (void *)android_net_utils_removeDefaultRoute },
     { "resetConnections", "(Ljava/lang/String;)I",  (void *)android_net_utils_resetConnections },
     { "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z",  (void *)android_net_utils_runDhcp },
+    { "runDhcpRenew", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z",  (void *)android_net_utils_runDhcpRenew },
     { "stopDhcp", "(Ljava/lang/String;)Z",  (void *)android_net_utils_stopDhcp },
     { "releaseDhcpLease", "(Ljava/lang/String;)Z",  (void *)android_net_utils_releaseDhcpLease },
     { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
@@ -229,7 +280,6 @@
     LOG_FATAL_IF(dhcpInfoInternalClass == NULL, "Unable to find class android/net/DhcpInfoInternal");
     dhcpInfoInternalFieldIds.constructorId = env->GetMethodID(dhcpInfoInternalClass, "<init>", "()V");
     dhcpInfoInternalFieldIds.ipaddress = env->GetFieldID(dhcpInfoInternalClass, "ipAddress", "Ljava/lang/String;");
-    dhcpInfoInternalFieldIds.gateway = env->GetFieldID(dhcpInfoInternalClass, "gateway", "Ljava/lang/String;");
     dhcpInfoInternalFieldIds.prefixLength = env->GetFieldID(dhcpInfoInternalClass, "prefixLength", "I");
     dhcpInfoInternalFieldIds.dns1 = env->GetFieldID(dhcpInfoInternalClass, "dns1", "Ljava/lang/String;");
     dhcpInfoInternalFieldIds.dns2 = env->GetFieldID(dhcpInfoInternalClass, "dns2", "Ljava/lang/String;");
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index 9d17fe9..e930c5c 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -419,7 +419,9 @@
     }
     // reply comes back in the form "powermode = XX" where XX is the
     // number we're interested in.
-    sscanf(reply, "%*s = %u", &power);
+    if (sscanf(reply, "%*s = %u", &power) != 1) {
+        return (jint)-1;
+    }
     return (jint)power;
 }
 
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 0681195..b432d65 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -282,6 +282,16 @@
             code, (int32_t)&data, (int32_t)reply, flags);
         jthrowable excep = env->ExceptionOccurred();
 
+        if (excep) {
+            report_exception(env, excep,
+                "*** Uncaught remote exception!  "
+                "(Exceptions are not yet supported across processes.)");
+            res = JNI_FALSE;
+
+            /* clean up JNI local ref -- we don't return to Java code */
+            env->DeleteLocalRef(excep);
+        }
+
         // Restore the Java binder thread's state if it changed while
         // processing a call (as it would if the Parcel's header had a
         // new policy mask and Parcel.enforceInterface() changed
@@ -294,14 +304,12 @@
             set_dalvik_blockguard_policy(env, strict_policy_before);
         }
 
-        if (excep) {
-            report_exception(env, excep,
-                "*** Uncaught remote exception!  "
-                "(Exceptions are not yet supported across processes.)");
-            res = JNI_FALSE;
-
+        jthrowable excep2 = env->ExceptionOccurred();
+        if (excep2) {
+            report_exception(env, excep2,
+                "*** Uncaught exception in onBinderStrictModePolicyChange");
             /* clean up JNI local ref -- we don't return to Java code */
-            env->DeleteLocalRef(excep);
+            env->DeleteLocalRef(excep2);
         }
 
         //aout << "onTransact to Java code; result=" << res << endl
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index af7639a..d43a27f 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -24,6 +24,8 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/ResourceTypes.h>
 
+#include <gui/SurfaceTexture.h>
+
 #include <SkBitmap.h>
 #include <SkCanvas.h>
 #include <SkMatrix.h>
@@ -517,6 +519,11 @@
     return redraw;
 }
 
+static void android_view_GLES20Canvas_outputDisplayList(JNIEnv* env,
+        jobject clazz, OpenGLRenderer* renderer, DisplayList* displayList) {
+    renderer->outputDisplayList(displayList);
+}
+
 // ----------------------------------------------------------------------------
 // Layers
 // ----------------------------------------------------------------------------
@@ -577,10 +584,13 @@
 }
 
 static void android_view_GLES20Canvas_updateTextureLayer(JNIEnv* env, jobject clazz,
-        Layer* layer, jint width, jint height, jfloatArray texTransform) {
-    jfloat* transform = env->GetFloatArrayElements(texTransform, NULL);
-    LayerRenderer::updateTextureLayer(layer, width, height, transform);
-    env->ReleaseFloatArrayElements(texTransform, transform, 0);
+        Layer* layer, jint width, jint height, SurfaceTexture* surface) {
+    float transform[16];
+    surface->updateTexImage();
+    surface->getTransformMatrix(transform);
+    GLenum renderTarget = surface->getCurrentTextureTarget();
+
+    LayerRenderer::updateTextureLayer(layer, width, height, renderTarget, transform);
 }
 
 static void android_view_GLES20Canvas_destroyLayer(JNIEnv* env, jobject clazz, Layer* layer) {
@@ -709,7 +719,7 @@
     { "nGetDisplayListRenderer", "(I)I",       (void*) android_view_GLES20Canvas_getDisplayListRenderer },
     { "nDrawDisplayList",        "(IIIILandroid/graphics/Rect;)Z",
                                                (void*) android_view_GLES20Canvas_drawDisplayList },
-
+    { "nOutputDisplayList",      "(II)V",      (void*) android_view_GLES20Canvas_outputDisplayList },
     { "nInterrupt",              "(I)V",       (void*) android_view_GLES20Canvas_interrupt },
     { "nResume",                 "(I)V",       (void*) android_view_GLES20Canvas_resume },
 
@@ -717,7 +727,7 @@
     { "nCreateLayer",            "(IIZ[I)I",   (void*) android_view_GLES20Canvas_createLayer },
     { "nResizeLayer",            "(III[I)V" ,  (void*) android_view_GLES20Canvas_resizeLayer },
     { "nCreateTextureLayer",     "([I)I",      (void*) android_view_GLES20Canvas_createTextureLayer },
-    { "nUpdateTextureLayer",     "(III[F)V" ,  (void*) android_view_GLES20Canvas_updateTextureLayer },
+    { "nUpdateTextureLayer",     "(IIII)V",    (void*) android_view_GLES20Canvas_updateTextureLayer },
     { "nDestroyLayer",           "(I)V",       (void*) android_view_GLES20Canvas_destroyLayer },
     { "nDestroyLayerDeferred",   "(I)V",       (void*) android_view_GLES20Canvas_destroyLayerDeferred },
     { "nDrawLayer",              "(IIFFI)V",   (void*) android_view_GLES20Canvas_drawLayer },
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
new file mode 100644
index 0000000..c5d86c8
--- /dev/null
+++ b/core/jni/android_view_TextureView.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2011 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 "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+
+#include <gui/SurfaceTexture.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+// Native layer
+// ----------------------------------------------------------------------------
+
+static void android_view_TextureView_setDefaultBufferSize(JNIEnv* env, jobject,
+    jint surfaceTexture, jint width, jint height) {
+
+    sp<SurfaceTexture> surface = reinterpret_cast<SurfaceTexture*>(surfaceTexture);
+    surface->setDefaultBufferSize(width, height);
+}
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+const char* const kClassPathName = "android/view/TextureView";
+
+static JNINativeMethod gMethods[] = {
+    {   "nSetDefaultBufferSize", "(III)V", (void*) android_view_TextureView_setDefaultBufferSize }
+};
+
+int register_android_view_TextureView(JNIEnv* env) {
+    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+};
diff --git a/core/jni/android_view_ViewRoot.cpp b/core/jni/android_view_ViewAncestor.cpp
similarity index 91%
rename from core/jni/android_view_ViewRoot.cpp
rename to core/jni/android_view_ViewAncestor.cpp
index 2988ae8..d8e1124 100644
--- a/core/jni/android_view_ViewRoot.cpp
+++ b/core/jni/android_view_ViewAncestor.cpp
@@ -35,7 +35,7 @@
 
 static int gPrevDur;
 
-static void android_view_ViewRoot_showFPS(JNIEnv* env, jobject, jobject jcanvas,
+static void android_view_ViewAncestor_showFPS(JNIEnv* env, jobject, jobject jcanvas,
                                           jint dur) {
     NPE_CHECK_RETURN_VOID(env, jcanvas);
     SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
@@ -79,14 +79,14 @@
 
 // ----------------------------------------------------------------------------
 
-const char* const kClassPathName = "android/view/ViewRoot";
+const char* const kClassPathName = "android/view/ViewAncestor";
 
 static JNINativeMethod gMethods[] = {
     {   "nativeShowFPS", "(Landroid/graphics/Canvas;I)V",
-                                        (void*)android_view_ViewRoot_showFPS }
+                                        (void*)android_view_ViewAncestor_showFPS }
 };
 
-int register_android_view_ViewRoot(JNIEnv* env) {
+int register_android_view_ViewAncestor(JNIEnv* env) {
     return AndroidRuntime::registerNativeMethods(env,
             kClassPathName, gMethods, NELEM(gMethods));
 }
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 5f2065a..f777527 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -27,6 +27,9 @@
 #include <SkBitmap.h>
 #include <SkPixelRef.h>
 
+#include <gui/SurfaceTexture.h>
+#include <gui/SurfaceTextureClient.h>
+
 namespace android {
 
 static jclass gConfig_class;
@@ -319,6 +322,35 @@
     return (jint)sur;
 }
 
+static jint jni_eglCreateWindowSurfaceTexture(JNIEnv *_env, jobject _this, jobject display,
+        jobject config, jint native_window, jintArray attrib_list) {
+    if (display == NULL || config == NULL
+        || !validAttribList(_env, attrib_list)) {
+        jniThrowException(_env, "java/lang/IllegalArgumentException", NULL);
+        return JNI_FALSE;
+    }
+    EGLDisplay dpy = getDisplay(_env, display);
+    EGLContext cnf = getConfig(_env, config);
+    sp<ANativeWindow> window;
+    if (native_window == 0) {
+not_valid_surface:
+        jniThrowException(_env, "java/lang/IllegalArgumentException",
+                "Make sure the SurfaceTexture is valid");
+        return 0;
+    }
+    
+    sp<SurfaceTexture> surfaceTexture = reinterpret_cast<SurfaceTexture*>(native_window);
+
+    window = new SurfaceTextureClient(surfaceTexture);
+    if (window == NULL)
+        goto not_valid_surface;
+
+    jint* base = beginNativeAttribList(_env, attrib_list);
+    EGLSurface sur = eglCreateWindowSurface(dpy, cnf, window.get(), base);
+    endNativeAttributeList(_env, attrib_list, base);
+    return (jint)sur;
+}
+
 static jboolean jni_eglGetConfigAttrib(JNIEnv *_env, jobject _this, jobject display,
         jobject config, jint attribute, jintArray value) {
     if (display == NULL || config == NULL
@@ -508,6 +540,7 @@
 {"_eglCreatePbufferSurface","(" DISPLAY CONFIG "[I)I", (void*)jni_eglCreatePbufferSurface },
 {"_eglCreatePixmapSurface", "(" SURFACE DISPLAY CONFIG OBJECT "[I)V", (void*)jni_eglCreatePixmapSurface },
 {"_eglCreateWindowSurface", "(" DISPLAY CONFIG OBJECT "[I)I", (void*)jni_eglCreateWindowSurface },
+{"_eglCreateWindowSurfaceTexture", "(" DISPLAY CONFIG "I[I)I", (void*)jni_eglCreateWindowSurfaceTexture },
 {"eglDestroyContext",      "(" DISPLAY CONTEXT ")Z", (void*)jni_eglDestroyContext },
 {"eglDestroySurface",      "(" DISPLAY SURFACE ")Z", (void*)jni_eglDestroySurface },
 {"eglMakeCurrent",         "(" DISPLAY SURFACE SURFACE CONTEXT")Z", (void*)jni_eglMakeCurrent },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2ed39e4..1c4bffd 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -496,6 +496,12 @@
         android:label="@string/permlab_hardware_test"
         android:description="@string/permdesc_hardware_test" />
 
+    <!-- Allows access to configure network interfaces, configure/use IPSec, etc.
+         @hide -->
+    <permission android:name="android.permission.NET_ADMIN"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="signature" />
+
     <!-- =========================================== -->
     <!-- Permissions associated with telephony state -->
     <!-- =========================================== -->
diff --git a/core/res/res/drawable-hdpi/stat_sys_adb.png b/core/res/res/drawable-hdpi/stat_sys_adb.png
index 9c56e24..615e8b3 100755
--- a/core/res/res/drawable-hdpi/stat_sys_adb.png
+++ b/core/res/res/drawable-hdpi/stat_sys_adb.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_adb.png b/core/res/res/drawable-mdpi/stat_sys_adb.png
index 1400bb3..6ba480d 100644
--- a/core/res/res/drawable-mdpi/stat_sys_adb.png
+++ b/core/res/res/drawable-mdpi/stat_sys_adb.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.png b/core/res/res/drawable-nodpi/platlogo.png
index 67e6ac3..c235005 100644
--- a/core/res/res/drawable-nodpi/platlogo.png
+++ b/core/res/res/drawable-nodpi/platlogo.png
Binary files differ
diff --git a/core/res/res/layout-xlarge/status_bar_latest_event_content.xml b/core/res/res/layout-xlarge/status_bar_latest_event_content.xml
deleted file mode 100644
index 676c38b..0000000
--- a/core/res/res/layout-xlarge/status_bar_latest_event_content.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    >
-    <ImageView android:id="@+id/icon"
-        android:layout_width="@dimen/notification_large_icon_width"
-        android:layout_height="@dimen/notification_large_icon_height"
-        android:background="@drawable/notify_panel_notification_icon_bg"
-        android:scaleType="center"
-        />
-    <LinearLayout
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical"
-        android:layout_weight="1"
-        android:orientation="vertical"
-        android:paddingLeft="16dp"
-        >
-        <TextView android:id="@+id/title"
-            android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:singleLine="true"
-            android:ellipsize="marquee"
-            android:fadingEdge="horizontal"
-            android:layout_marginBottom="-3dp"
-            />
-        <TextView android:id="@+id/text"
-            android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:layout_marginTop="-2dp"
-            android:singleLine="true"
-            android:ellipsize="marquee"
-            android:fadingEdge="horizontal"
-            />
-    </LinearLayout>
-    <TextView android:id="@+id/info"
-        android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:singleLine="true"
-        android:gravity="center_vertical"
-        android:paddingLeft="8dp"
-        />
-</LinearLayout>
-
diff --git a/core/res/res/layout/action_bar_title_item.xml b/core/res/res/layout/action_bar_title_item.xml
index 0cf4222..d8b729d 100644
--- a/core/res/res/layout/action_bar_title_item.xml
+++ b/core/res/res/layout/action_bar_title_item.xml
@@ -28,5 +28,6 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:singleLine="true"
-        android:ellipsize="end" />
+        android:ellipsize="end"
+        android:visibility="gone" />
 </LinearLayout>
diff --git a/core/res/res/layout/screen_action_bar.xml b/core/res/res/layout/screen_action_bar.xml
index 14af446..9742b94 100644
--- a/core/res/res/layout/screen_action_bar.xml
+++ b/core/res/res/layout/screen_action_bar.xml
@@ -43,7 +43,7 @@
         android:layout_weight="1"
         android:foregroundGravity="fill_horizontal|top"
         android:foreground="?android:attr/windowContentOverlay" />
-    <LinearLayout android:id="@+id/lower_action_context_bar"
+    <com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"
                   android:layout_width="match_parent"
                   android:layout_height="wrap_content"
                   style="?android:attr/actionBarStyle"
diff --git a/core/res/res/layout/screen_action_bar_overlay.xml b/core/res/res/layout/screen_action_bar_overlay.xml
index aebbe41..086acdd 100644
--- a/core/res/res/layout/screen_action_bar_overlay.xml
+++ b/core/res/res/layout/screen_action_bar_overlay.xml
@@ -46,7 +46,7 @@
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@id/action_bar_container" />
-    <LinearLayout android:id="@+id/lower_action_context_bar"
+    <com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"
                   android:layout_width="match_parent"
                   android:layout_height="wrap_content"
                   android:layout_alignParentBottom="true"
diff --git a/core/res/res/layout/status_bar_latest_event_content.xml b/core/res/res/layout/status_bar_latest_event_content.xml
index c64b90e..676c38b 100644
--- a/core/res/res/layout/status_bar_latest_event_content.xml
+++ b/core/res/res/layout/status_bar_latest_event_content.xml
@@ -1,56 +1,48 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        android:paddingTop="7dp"
-        android:paddingLeft="5dp"
-        >
-
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    >
+    <ImageView android:id="@+id/icon"
+        android:layout_width="@dimen/notification_large_icon_width"
+        android:layout_height="@dimen/notification_large_icon_height"
+        android:background="@drawable/notify_panel_notification_icon_bg"
+        android:scaleType="center"
+        />
     <LinearLayout
-        android:layout_width="match_parent"
+        android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:orientation="horizontal"
-        android:paddingTop="3dp"
+        android:layout_gravity="center_vertical"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:paddingLeft="16dp"
         >
-        <!--com.android.server.status.AnimatedImageView android:id="@+id/icon" -->
-        <ImageView android:id="@+id/icon"
-            android:layout_width="25dp"
-            android:layout_height="25dp"
-            android:scaleType="fitCenter"
-            android:src="@drawable/arrow_down_float"/>
         <TextView android:id="@+id/title"
             android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_weight="1"
             android:singleLine="true"
             android:ellipsize="marquee"
             android:fadingEdge="horizontal"
-            android:paddingLeft="4dp"
+            android:layout_marginBottom="-3dp"
             />
-    </LinearLayout>
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal"
-        >
         <TextView android:id="@+id/text"
             android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-            android:layout_width="wrap_content"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_weight="1"
+            android:layout_marginTop="-2dp"
             android:singleLine="true"
             android:ellipsize="marquee"
             android:fadingEdge="horizontal"
-            android:paddingLeft="4dp"
-            />
-        <android.widget.DateTimeView android:id="@+id/time"
-            android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-            android:layout_marginLeft="4dp"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:singleLine="true"
-            android:paddingRight="5dp"
             />
     </LinearLayout>
+    <TextView android:id="@+id/info"
+        android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:singleLine="true"
+        android:gravity="center_vertical"
+        android:paddingLeft="8dp"
+        />
 </LinearLayout>
+
diff --git a/core/res/res/layout-xlarge/status_bar_latest_event_content_large_icon.xml b/core/res/res/layout/status_bar_latest_event_content_large_icon.xml
similarity index 100%
rename from core/res/res/layout-xlarge/status_bar_latest_event_content_large_icon.xml
rename to core/res/res/layout/status_bar_latest_event_content_large_icon.xml
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index fbf4161..62e79f8 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -50,7 +50,7 @@
     <string name="needPuk2" msgid="4526033371987193070">"Escriviu el PUK2 per desbloquejar la targeta SIM."</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Identificació de trucada entrant"</string>
     <string name="ClirMmi" msgid="7784673673446833091">"Identificació de trucada de sortida"</string>
-    <string name="CfMmi" msgid="5123218989141573515">"Desviament de trucades"</string>
+    <string name="CfMmi" msgid="5123218989141573515">"Desviació de trucades"</string>
     <string name="CwMmi" msgid="9129678056795016867">"Trucada en espera"</string>
     <string name="BaMmi" msgid="455193067926770581">"Restricció de trucades"</string>
     <string name="PwdMmi" msgid="7043715687905254199">"Canvi de contrasenya"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 64da78f..acb9821 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -204,8 +204,8 @@
     <string name="permdesc_getTasks" msgid="7048711358713443341">"Ermöglicht der Anwendung, Informationen zu aktuellen und kürzlich ausführten Aufgaben abzurufen. Schädliche Anwendungen können so eventuell geheime Informationen zu anderen Anwendungen entdecken."</string>
     <string name="permlab_reorderTasks" msgid="5669588525059921549">"Laufende Anwendungen neu ordnen"</string>
     <string name="permdesc_reorderTasks" msgid="126252774270522835">"Ermöglicht einer Anwendung, Aufgaben in den Vorder- und Hintergrund zu verschieben. Schädliche Anwendungen können so ohne Ihr Zutun eine Anzeige im Vordergrund erzwingen."</string>
-    <string name="permlab_removeTasks" msgid="4802740047161700683">"Aktive Anwendungen beenden"</string>
-    <string name="permdesc_removeTasks" msgid="2000332928514575461">"Ermöglicht einer Anwendung das Entfernen von Aufgaben und Beenden der entsprechenden Anwendungen. Schädliche Anwendungen können das Verhalten anderer Anwendungen stören."</string>
+    <string name="permlab_removeTasks" msgid="4802740047161700683">"Aktive Apps beenden"</string>
+    <string name="permdesc_removeTasks" msgid="2000332928514575461">"Ermöglicht einer App das Entfernen von Aufgaben und Beenden der entsprechenden Apps. Schädliche Apps können das Verhalten anderer Apps stören."</string>
     <string name="permlab_setDebugApp" msgid="4339730312925176742">"Fehlerbeseitigung für Anwendung aktivieren"</string>
     <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Ermöglicht einer Anwendung, die Fehlerbeseitigung für eine andere Anwendung zu aktivieren. Schädliche Anwendungen können so andere Anwendungen löschen."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI-Einstellungen ändern"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 373f76c..2f1a1ad 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -466,7 +466,7 @@
     <string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"modificar/eliminar contenido de la tarjeta SD"</string>
     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6594393334785738252">"Permite escribir en USB"</string>
     <string name="permdesc_sdcardWrite" product="default" msgid="6643963204976471878">"Permite que una aplicación escriba en la tarjeta SD."</string>
-    <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Cambiar/borrar almac interno"</string>
+    <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modificar o eliminar el contenido del almacenamiento de medios interno"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8232008512478316233">"Permite que una aplicación modifique el contenido del almacenamiento interno de medios."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"acceder al sistema de archivos almacenado en caché"</string>
     <string name="permdesc_cache_filesystem" msgid="1624734528435659906">"Permite que una aplicación lea y escriba el sistema de archivos almacenado en caché."</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 1f0a94c..f112c33 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -204,7 +204,7 @@
     <string name="permdesc_getTasks" msgid="7048711358713443341">"Mengizinkan aplikasi mengambil informasi tentang tugas yang sedang dan baru saja dijalankan. Aplikasi hasad dapat menemukan informasi bajakan tentang aplikasi lain."</string>
     <string name="permlab_reorderTasks" msgid="5669588525059921549">"atur urutan aplikasi yang berjalan"</string>
     <string name="permdesc_reorderTasks" msgid="126252774270522835">"Mengizinkan aplikasi memindah tugas ke latar depan dan latar belakang. Aplikasi hasad dapat memaksa dirinya ke latar depan tanpa sepengetahuan Anda."</string>
-    <string name="permlab_removeTasks" msgid="4802740047161700683">"berhenti menjalankan aplikasi"</string>
+    <string name="permlab_removeTasks" msgid="4802740047161700683">"menghentikan aplikasi yang berjalan"</string>
     <string name="permdesc_removeTasks" msgid="2000332928514575461">"Memungkinkan aplikasi menghapus tugas dan menghentikan aplikasinya. Aplikasi jahat dapat mengganggu perilaku aplikasi lain."</string>
     <string name="permlab_setDebugApp" msgid="4339730312925176742">"aktifkan debugging aplikasi"</string>
     <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Mengizinkan aplikasi menghidupkan debug untuk aplikasi lain. Aplikasi hasad dapat menggunakan ini untuk menghentikan aplikasi penting lainnya."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 4d2b6c35..4d36eb3 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -204,8 +204,8 @@
     <string name="permdesc_getTasks" msgid="7048711358713443341">"Permite aplicaţiei să regăsească informaţii despre activităţile rulate curent şi recent. Poate permite aplicaţiilor rău-intenţionate să descopere informaţii confidenţiale despre alte aplicaţii."</string>
     <string name="permlab_reorderTasks" msgid="5669588525059921549">"reordonare aplicaţii aflate în derulare"</string>
     <string name="permdesc_reorderTasks" msgid="126252774270522835">"Permite unei aplicaţii să mute activităţile în prim-plan şi în fundal. Aplicaţiile rău-intenţionate ar putea să apară forţat în prim-plan, fără ca dvs. să puteţi controla acest lucru."</string>
-    <string name="permlab_removeTasks" msgid="4802740047161700683">"opriţi aplicaţiile care rulează"</string>
-    <string name="permdesc_removeTasks" msgid="2000332928514575461">"Permite unei aplicaţii să elimine sarcinile şi să închidă aplicaţiile corespunzătoare acestora. Aplicaţiile rău intenţionate pot perturba comportamentul altor aplicaţii."</string>
+    <string name="permlab_removeTasks" msgid="4802740047161700683">"oprirea aplicaţiilor care rulează"</string>
+    <string name="permdesc_removeTasks" msgid="2000332928514575461">"Permite unei aplicaţii să elimine sarcini şi să închidă aplicaţiile corespunzătoare acestora. Aplicaţiile rău intenţionate pot perturba comportamentul altor aplicaţii."</string>
     <string name="permlab_setDebugApp" msgid="4339730312925176742">"activare depanare aplicaţie"</string>
     <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Permite unei aplicaţii să activeze depanarea pentru o altă aplicaţie. Aplicaţiile rău-intenţionate ar putea să utilizeze această permisiune pentru a închide alte aplicaţii."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"modificare setări UI"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 6155536..a81b2ee 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -205,7 +205,7 @@
     <string name="permlab_reorderTasks" msgid="5669588525059921549">"zmena usporiadania spustených aplikácií"</string>
     <string name="permdesc_reorderTasks" msgid="126252774270522835">"Umožňuje aplikácii presúvať úlohy do popredia alebo pozadia. Škodlivé aplikácie môžu vynútiť svoje presunutia do popredia bez vášho pričinenia."</string>
     <string name="permlab_removeTasks" msgid="4802740047161700683">"zastavenie činnosti aplikácií"</string>
-    <string name="permdesc_removeTasks" msgid="2000332928514575461">"Umožňuje aplikácii odstraňovať úlohy a ukončiť čínnosť súvisiacich aplikácií. Škodlivé aplikácie môžu narušovať správanie iných aplikácií."</string>
+    <string name="permdesc_removeTasks" msgid="2000332928514575461">"Umožňuje aplikácii odstraňovať úlohy a ukončiť činnosť súvisiacich aplikácií. Škodlivé aplikácie môžu narušovať správanie iných aplikácií."</string>
     <string name="permlab_setDebugApp" msgid="4339730312925176742">"povoliť ladenie aplikácií"</string>
     <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Umožňuje aplikácii povoliť ladenie inej aplikácie. Škodlivé aplikácie môžu pomocou tohto nastavenia ukončiť iné aplikácie."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"zmeny vašich nastavení používateľského rozhrania"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 9c234a7..545be31 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -205,7 +205,7 @@
     <string name="permlab_reorderTasks" msgid="5669588525059921549">"重新安排執行中的應用程式"</string>
     <string name="permdesc_reorderTasks" msgid="126252774270522835">"允許應用程式將工作移至前端或背景作業。請注意:惡意程式可能使用此功能自行把自己拉到前端。"</string>
     <string name="permlab_removeTasks" msgid="4802740047161700683">"停止執行中的應用程式"</string>
-    <string name="permdesc_removeTasks" msgid="2000332928514575461">"允許應用程式移除工作並且關閉應用程式。惡意應用程式會干擾其他應用程式的行為。"</string>
+    <string name="permdesc_removeTasks" msgid="2000332928514575461">"允許應用程式移除工作並且關閉應用程式。惡意應用程式會干擾其他應用程式的運行。"</string>
     <string name="permlab_setDebugApp" msgid="4339730312925176742">"啟用應用程式偵錯"</string>
     <string name="permdesc_setDebugApp" msgid="5584310661711990702">"允許應用程式為其他程式開啟偵錯功能。請注意:惡意程式可利用此功能終止其他應用程式。"</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"變更介面設定"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3480604..620d293 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -144,17 +144,20 @@
          attributes.  This is used by the connectivity manager to decide which networks can coexist
          based on the hardware -->
     <!-- An Array of "[Connection name],[ConnectivityManager connection type],
-         [associated radio-type],[priority],[dependencyMet]  -->
-    <!-- the 5th element indicates boot-time dependency-met value. -->
+         [associated radio-type],[priority],[restoral-timer(ms)],[dependencyMet]  -->
+    <!-- the 5th element "resore-time" indicates the number of milliseconds to delay
+         before automatically restore the default connection.  Set -1 if the connection
+         does not require auto-restore. -->
+    <!-- the 6th element indicates boot-time dependency-met value. -->
     <string-array translatable="false" name="networkAttributes">
-        <item>"wifi,1,1,1,true"</item>
-        <item>"mobile,0,0,0,true"</item>
-        <item>"mobile_mms,2,0,2,true"</item>
-        <item>"mobile_supl,3,0,2,true"</item>
-        <item>"mobile_hipri,5,0,3,true"</item>
-        <item>"mobile_fota,10,0,2,true"</item>
-        <item>"mobile_ims,11,0,2,true"</item>
-        <item>"mobile_cbs,12,0,2,true"</item>
+        <item>"wifi,1,1,1,-1,true"</item>
+        <item>"mobile,0,0,0,-1,true"</item>
+        <item>"mobile_mms,2,0,2,60000,true"</item>
+        <item>"mobile_supl,3,0,2,60000,true"</item>
+        <item>"mobile_hipri,5,0,3,60000,true"</item>
+        <item>"mobile_fota,10,0,2,60000,true"</item>
+        <item>"mobile_ims,11,0,2,60000,true"</item>
+        <item>"mobile_cbs,12,0,2,60000,true"</item>
     </string-array>
 
     <!-- This string array should be overridden by the device to present a list of radio
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index bc419ec..fa662ed 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2815,4 +2815,10 @@
     <!-- Description of the button to decrement the NumberPicker value. [CHAR LIMIT=NONE] -->
     <string name="number_picker_decrement_button">Decrement</string>
 
+    <!-- Content description for the action bar "home" affordance. [CHAR LIMIT=NONE] -->
+    <string name="action_bar_home_description">Navigate home</string>
+    <!-- Content description for the action bar "up" affordance. [CHAR LIMIT=NONE] -->
+    <string name="action_bar_up_description">Navigate up</string>
+    <!-- Content description for the action menu overflow button. [CHAR LIMIT=NONE] -->
+    <string name="action_menu_overflow_description">More options</string>
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index e666698..2d44f62 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -217,7 +217,6 @@
 
     <style name="TextAppearance.StatusBar">
         <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
     </style>
     <style name="TextAppearance.StatusBar.Ticker">
     </style>
@@ -226,15 +225,13 @@
     </style>
 
     <style name="TextAppearance.StatusBar.Icon">
-        <item name="android:textStyle">bold</item>
     </style>
     <style name="TextAppearance.StatusBar.EventContent">
-        <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
-        <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
+        <item name="android:textColor">#ff999999</item>
+        <item name="android:textSize">14sp</item>
     </style>
     <style name="TextAppearance.StatusBar.EventContent.Title">
-        <item name="android:textSize">18sp</item>
-        <item name="android:textStyle">bold</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
     </style>
     <style name="TextAppearance.StatusBar.EventContent.Info">
         <item name="android:textAppearance">?android:attr/textAppearanceLarge</item>
@@ -1117,7 +1114,7 @@
 
     <style name="Widget.ActionButton.Overflow">
         <item name="android:src">@drawable/ic_menu_more</item>
-        <item name="android:contentDescription">@string/more_item_label</item>
+        <item name="android:contentDescription">@string/action_menu_overflow_description</item>
     </style>
 
     <style name="Widget.ActionButton.CloseMode">
@@ -1778,6 +1775,7 @@
         <item name="android:background">?android:attr/selectableItemBackground</item>
         <item name="android:paddingLeft">16dip</item>
         <item name="android:paddingRight">16dip</item>
+        <item name="android:contentDescription">@string/action_menu_overflow_description</item>
     </style>
 
     <style name="Widget.Holo.ActionButton.TextButton" parent="Widget.Holo.ButtonBar.Button">
@@ -2112,6 +2110,7 @@
         <item name="android:src">@android:drawable/ic_menu_moreoverflow_holo_light</item>
         <item name="android:paddingLeft">16dip</item>
         <item name="android:paddingRight">16dip</item>
+        <item name="android:contentDescription">@string/action_menu_overflow_description</item>
     </style>
 
     <style name="Widget.Holo.Light.ActionBarView_TabView" parent="Widget.Holo.ActionBarView_TabView">
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
index d22356d..27363e8 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
@@ -30,6 +30,7 @@
 import android.net.wifi.WifiConfiguration.ProxySettings;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
+import android.net.RouteInfo;
 import android.util.Log;
 
 import java.io.InputStream;
@@ -301,7 +302,7 @@
                     if (!InetAddress.isNumeric(gwAddr)) {
                         throw new SAXException();
                     }
-                    mLinkProperties.addGateway(InetAddress.getByName(gwAddr));
+                    mLinkProperties.addRoute(new RouteInfo(InetAddress.getByName(gwAddr)));
                 } catch (UnknownHostException e) {
                     throw new SAXException();
                 }
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 010e3c3..fadf1ec 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -421,6 +421,13 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.widget.scroll.arrowscroll.MultiPageTextWithPadding" android:label="arrowscrollMultiPageTextWithPadding">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="android.view.Include" android:label="IncludeTag">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
index 50666b4..e3b6b5f 100644
--- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java
+++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.net.LinkProperties;
+import android.net.RouteInfo;
 import android.test.suitebuilder.annotation.SmallTest;
 import junit.framework.TestCase;
 
@@ -55,8 +56,8 @@
             source.addDns(NetworkUtils.numericToInetAddress(DNS1));
             source.addDns(NetworkUtils.numericToInetAddress(DNS2));
             // set 2 gateways
-            source.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
-            source.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+            source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+            source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
 
             LinkProperties target = new LinkProperties();
 
@@ -68,8 +69,8 @@
                     NetworkUtils.numericToInetAddress(ADDRV6), 128));
             target.addDns(NetworkUtils.numericToInetAddress(DNS1));
             target.addDns(NetworkUtils.numericToInetAddress(DNS2));
-            target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
-            target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
 
             assertTrue(source.equals(target));
             assertTrue(source.hashCode() == target.hashCode());
@@ -83,8 +84,8 @@
                     NetworkUtils.numericToInetAddress(ADDRV6), 128));
             target.addDns(NetworkUtils.numericToInetAddress(DNS1));
             target.addDns(NetworkUtils.numericToInetAddress(DNS2));
-            target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
-            target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
             assertFalse(source.equals(target));
 
             target.clear();
@@ -96,8 +97,8 @@
                     NetworkUtils.numericToInetAddress(ADDRV6), 128));
             target.addDns(NetworkUtils.numericToInetAddress(DNS1));
             target.addDns(NetworkUtils.numericToInetAddress(DNS2));
-            target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
-            target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
             assertFalse(source.equals(target));
 
             target.clear();
@@ -109,8 +110,8 @@
             // change dnses
             target.addDns(NetworkUtils.numericToInetAddress("75.208.7.2"));
             target.addDns(NetworkUtils.numericToInetAddress(DNS2));
-            target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
-            target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
             assertFalse(source.equals(target));
 
             target.clear();
@@ -122,8 +123,8 @@
             target.addDns(NetworkUtils.numericToInetAddress(DNS1));
             target.addDns(NetworkUtils.numericToInetAddress(DNS2));
             // change gateway
-            target.addGateway(NetworkUtils.numericToInetAddress("75.208.8.2"));
-            target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2")));
+            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
             assertFalse(source.equals(target));
 
         } catch (Exception e) {
@@ -146,8 +147,8 @@
             source.addDns(NetworkUtils.numericToInetAddress(DNS1));
             source.addDns(NetworkUtils.numericToInetAddress(DNS2));
             // set 2 gateways
-            source.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
-            source.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+            source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+            source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
 
             LinkProperties target = new LinkProperties();
             // Exchange order
@@ -158,8 +159,8 @@
                     NetworkUtils.numericToInetAddress(ADDRV4), 32));
             target.addDns(NetworkUtils.numericToInetAddress(DNS2));
             target.addDns(NetworkUtils.numericToInetAddress(DNS1));
-            target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
-            target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
+            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
 
             assertTrue(source.equals(target));
             assertTrue(source.hashCode() == target.hashCode());
diff --git a/core/tests/coretests/src/android/text/TextUtilsTest.java b/core/tests/coretests/src/android/text/TextUtilsTest.java
index c82962d..d494c5d 100644
--- a/core/tests/coretests/src/android/text/TextUtilsTest.java
+++ b/core/tests/coretests/src/android/text/TextUtilsTest.java
@@ -19,6 +19,7 @@
 import com.google.android.collect.Lists;
 
 import android.test.MoreAsserts;
+import android.os.Parcel;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.text.style.StyleSpan;
@@ -344,6 +345,51 @@
         assertFalse(TextUtils.delimitedStringContains("network,mock,gpsx", ',', "gps"));
     }
 
+    @SmallTest
+    public void testCharSequenceCreator() {
+        Parcel p = Parcel.obtain();
+        TextUtils.writeToParcel(null, p, 0);
+        CharSequence text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
+        assertNull("null CharSequence should generate null from parcel", text);
+        p = Parcel.obtain();
+        TextUtils.writeToParcel("test", p, 0);
+        text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
+        assertEquals("conversion to/from parcel failed", "test", text);
+    }
+
+    @SmallTest
+    public void testCharSequenceCreatorNull() {
+        Parcel p;
+        CharSequence text;
+        p = Parcel.obtain();
+        TextUtils.writeToParcel(null, p, 0);
+        p.setDataPosition(0);
+        text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
+        assertNull("null CharSequence should generate null from parcel", text);
+    }
+
+    @SmallTest
+    public void testCharSequenceCreatorSpannable() {
+        Parcel p;
+        CharSequence text;
+        p = Parcel.obtain();
+        TextUtils.writeToParcel(new SpannableString("test"), p, 0);
+        p.setDataPosition(0);
+        text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
+        assertEquals("conversion to/from parcel failed", "test", text.toString());
+    }
+
+    @SmallTest
+    public void testCharSequenceCreatorString() {
+        Parcel p;
+        CharSequence text;
+        p = Parcel.obtain();
+        TextUtils.writeToParcel("test", p, 0);
+        p.setDataPosition(0);
+        text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
+        assertEquals("conversion to/from parcel failed", "test", text.toString());
+    }
+
     /**
      * CharSequence wrapper for testing the cases where text is copied into
      * a char array instead of working from a String or a Spanned.
diff --git a/core/tests/coretests/src/android/util/ScrollViewScenario.java b/core/tests/coretests/src/android/util/ScrollViewScenario.java
index 83afe06..db3d9d0 100644
--- a/core/tests/coretests/src/android/util/ScrollViewScenario.java
+++ b/core/tests/coretests/src/android/util/ScrollViewScenario.java
@@ -61,6 +61,7 @@
 
     /**
      * Partially implement ViewFactory given a height ratio.
+     * A negative height ratio means that WRAP_CONTENT will be used as height
      */
     private static abstract class ViewFactoryBase implements ViewFactory {
 
@@ -87,6 +88,9 @@
 
         List<ViewFactory> mViewFactories = Lists.newArrayList();
 
+        int mTopPadding = 0;
+        int mBottomPadding = 0;
+
         /**
          * Add a text view.
          * @param text The text of the text view.
@@ -186,6 +190,13 @@
             });
             return this;
         }
+
+        public Params addPaddingToScrollView(int topPadding, int bottomPadding) {
+            mTopPadding = topPadding;
+            mBottomPadding = bottomPadding;
+
+            return this;
+        }
     }
 
     /**
@@ -239,13 +250,17 @@
 
         // create views specified by params
         for (ViewFactory viewFactory : params.mViewFactories) {
+            int height = ViewGroup.LayoutParams.WRAP_CONTENT;
+            if (viewFactory.getHeightRatio() >= 0) {
+                height = (int) (viewFactory.getHeightRatio() * screenHeight);
+            }
             final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
-                    ViewGroup.LayoutParams.MATCH_PARENT,
-                    (int) (viewFactory.getHeightRatio() * screenHeight));
+                    ViewGroup.LayoutParams.MATCH_PARENT, height);
             mLinearLayout.addView(viewFactory.create(this), lp);
         }
 
         mScrollView = createScrollView();
+        mScrollView.setPadding(0, params.mTopPadding, 0, params.mBottomPadding);
         mScrollView.addView(mLinearLayout, new ViewGroup.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.MATCH_PARENT));
diff --git a/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java b/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
index 477831e..909a8c9 100644
--- a/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
+++ b/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
@@ -90,7 +90,7 @@
             fail("requestFocus from wrong thread should raise exception.");
         } catch (AndroidRuntimeException e) {
             // Expected.  The actual exception is not public, so we can't catch it.
-            assertEquals("android.view.ViewRoot$CalledFromWrongThreadException",
+            assertEquals("android.view.ViewAncestor$CalledFromWrongThreadException",
                          e.getClass().getName());
         }
     }
diff --git a/core/tests/coretests/src/android/widget/listview/ListViewHeight.java b/core/tests/coretests/src/android/widget/listview/ListViewHeight.java
index 64f280a..5cf3ff6 100644
--- a/core/tests/coretests/src/android/widget/listview/ListViewHeight.java
+++ b/core/tests/coretests/src/android/widget/listview/ListViewHeight.java
@@ -88,7 +88,7 @@
 
         // Clicking this button will remove the list adapter and hide the outer enclosing view.
         // We have to climb all the way to the top because the bug (not checking visibility)
-        // only occurs at the very outer loop of ViewRoot.performTraversals and in the case of
+        // only occurs at the very outer loop of ViewAncestor.performTraversals and in the case of
         // an Activity, this means you have to crawl all the way out to the root view.
         // In the search manager, it's sufficient to simply show/hide the outer search manager
         // view to trigger the same bug.
diff --git a/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPadding.java b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPadding.java
new file mode 100644
index 0000000..7d5a8d8
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPadding.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget.scroll.arrowscroll;
+
+import android.util.ScrollViewScenario;
+
+/**
+ * One TextView with a text covering several pages. Padding is added
+ * above and below the ScrollView.
+ */
+public class MultiPageTextWithPadding extends ScrollViewScenario {
+
+    @Override
+    protected void init(Params params) {
+
+        String text = "This is a long text.";
+        String longText = "First text.";
+        for (int i = 0; i < 300; i++) {
+            longText = longText + " " + text;
+        }
+        longText = longText + " Last text.";
+        params.addTextView(longText, -1.0f).addPaddingToScrollView(50, 50);
+    }
+}
diff --git a/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java
new file mode 100644
index 0000000..ddde48f
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2011 Sony Ericsson Mobile Communications AB.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget.scroll.arrowscroll;
+
+import android.widget.scroll.arrowscroll.MultiPageTextWithPadding;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.TextView;
+import android.widget.ScrollView;
+
+public class MultiPageTextWithPaddingTest extends
+        ActivityInstrumentationTestCase<MultiPageTextWithPadding> {
+
+    private ScrollView mScrollView;
+
+    private TextView mTextView;
+
+    public MultiPageTextWithPaddingTest() {
+        super("com.android.frameworks.coretests", MultiPageTextWithPadding.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mScrollView = getActivity().getScrollView();
+        mTextView = getActivity().getContentChildAt(0);
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertTrue("text should not fit on screen",
+                   mTextView.getHeight() > mScrollView.getHeight());
+    }
+
+    @LargeTest
+    public void testScrollDownToBottom() throws Exception {
+        // Calculate the number of arrow scrolls needed to reach the bottom
+        int scrollsNeeded = (int)Math.ceil(Math.max(0.0f,
+                (mTextView.getHeight() - mScrollView.getHeight()))
+                / mScrollView.getMaxScrollAmount());
+        for (int i = 0; i < scrollsNeeded; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+
+        assertEquals(
+                "should be fully scrolled to bottom",
+                getActivity().getLinearLayout().getHeight()
+                        - (mScrollView.getHeight() - mScrollView.getPaddingTop() - mScrollView
+                                .getPaddingBottom()), mScrollView.getScrollY());
+    }
+}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 1870a4a..5ed7966 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -66,6 +66,10 @@
         <group gid="mtp" />
     </permission>
 
+    <permission name="android.permission.NET_ADMIN" >
+        <group gid="net_admin" />
+    </permission>
+
     <!-- The group that /cache belongs to, linked to the permission
          set on the applications that can access /cache -->
     <permission name="android.permission.ACCESS_CACHE_FILESYSTEM" >
diff --git a/docs/html/guide/developing/building/building-cmdline.jd b/docs/html/guide/developing/building/building-cmdline.jd
index 5f193bc..ec918dc 100644
--- a/docs/html/guide/developing/building/building-cmdline.jd
+++ b/docs/html/guide/developing/building/building-cmdline.jd
@@ -6,16 +6,27 @@
  <div id="qv-wrapper">
     <div id="qv">
       <h2>In this document</h2>
-
       <ol>
-        <li><a href="#DebugMode">Building in debug mode</a></li>
-
-        <li><a href="#ReleaseMode">Building in release mode</a></li>
-
-        <li><a href="#RunningOnEmulator">Running on an emulator</a></li>
-
-        <li><a href="#RunningOnDevice">Running on a device</a></li>
+        <li><a href="#DebugMode">Building in Debug Mode</a></li>
+        <li><a href="#ReleaseMode">Building in Release Mode</a>
+          <ol>
+            <li><a href="#ManualReleaseMode">Build unsigned</a></li>
+            <li><a href="#AutoReleaseMode">Build signed and aligned</a></li>
+            <li><a href="#OnceBuilt">Once built and signed in release mode</a></li>
+          </ol>
+        </li>
+        <li><a href="#RunningOnEmulator">Running on the Emulator</a></li>
+        <li><a href="#RunningOnDevice">Running on a Device</a></li>
+        <li><a href="#Signing">Application Signing</a></li>
       </ol>
+  <h2>See also</h2>
+  <ol>
+    <li><a href="{@docRoot}guide/developing/devices/managing-avds-cmdline.html">Managing AVDs from
+the Command Line</a></li>
+    <li><a href="{@docRoot}guide/developing/devices/emulator.html">Using the Android
+Emulator</a></li>
+    <li><a href="{@docRoot}guide/publishing/app-signing.html">Signing Your Applications</a></li>
+  </ol>
     </div>
   </div>
 
@@ -54,7 +65,7 @@
   
   <pre>c:\java\jdk1.6.0_02</pre>
 
-  <h2 id="DebugMode">Building in debug mode</h2>
+  <h2 id="DebugMode">Building in Debug Mode</h2>
 
   <p>For immediate application testing and debugging, you can build your application in debug mode
   and immediately install it on an emulator. In debug mode, the build tools automatically sign your
@@ -83,7 +94,7 @@
   <p>To install and run your application on an emulator, see the following section about <a href=
   "#RunningOnEmulator">Running on the Emulator</a>.</p>
 
-  <h2 id="ReleaseMode">Building in release mode</h2>
+  <h2 id="ReleaseMode">Building in Release Mode</h2>
 
   <p>When you're ready to release and distribute your application to end-users, you must build your
   application in release mode. Once you have built in release mode, it's a good idea to perform
@@ -172,7 +183,7 @@
   been signed with the private key specified in {@code build.properties} and aligned with {@code
   zipalign}. It's ready for installation and distribution.</p>
 
-  <h3>Once built and signed in release mode</h3>
+  <h3 id="OnceBuilt">Once built and signed in release mode</h3>
 
   <p>Once you have signed your application with a private key, you can install and run it on an
   <a href="#RunningOnEmulator">emulator</a> or <a href="#RunningOnDevice">device</a>. You can 
@@ -181,7 +192,7 @@
   installation. (On your device, be sure you have enabled 
   <em>Settings &gt; Applications &gt; Unknown sources</em>.)</p>
 
-  <h2 id="RunningOnEmulator">Running on the emulator</h2>
+  <h2 id="RunningOnEmulator">Running on the Emulator</h2>
 
   <p>Before you can run your application on the Android Emulator, you must <a href=
   "{@docRoot}guide/developing/devices/managing-avds.html">create an AVD</a>.</p>
@@ -243,7 +254,7 @@
   install</code>. This will build your application, sign it with the debug key, and install it on
   the currently running emulator.</p>
 
-  <h2 id="RunningOnDevice">Running on a device</h2>
+  <h2 id="RunningOnDevice">Running on a Device</h2>
 
   <p>Before you can run your application on a device, you must perform some basic setup for your
   device:</p>
@@ -297,7 +308,7 @@
   <p>The ADT plugin helps you get started quickly by signing your .apk files with a debug key,
   prior to installing them on an emulator or development device. This means that you can quickly
   run your application from Eclipse without having to generate your own private key. No specific
-  action on your part is needed, provided ADT has access to Keytool.However, please note that if
+  action on your part is needed, provided ADT has access to Keytool. However, please note that if
   you intend to publish your application, you <strong>must</strong> sign the application with your
   own private key, rather than the debug key generated by the SDK tools.</p>
 
diff --git a/docs/html/guide/developing/devices/managing-avds-cmdline.jd b/docs/html/guide/developing/devices/managing-avds-cmdline.jd
index 6feeeb6..8674334 100644
--- a/docs/html/guide/developing/devices/managing-avds-cmdline.jd
+++ b/docs/html/guide/developing/devices/managing-avds-cmdline.jd
@@ -7,12 +7,25 @@
   <div id="qv">
   <h2>In this document</h2>
   <ol>
-    <li><a href="#listingtargets">Listing targets</a></li>
-    <li><a href="#AVDCmdLine">Creating AVDs</a></li>
+    <li><a href="#listingtargets">Listing Targets</a></li>
+    <li><a href="#AVDCmdLine">Creating AVDs</a>
+      <ol>
+        <li><a href="#CustomDensity">Customize the device resolution or density</a></li>
+        <li><a href="#DefaultLocation">Default location of AVD files</a></li>
+        <li><a href="#hardwareopts">Setting hardware emulation options</a></li>
+      </ol>
+    </li>
     <li><a href="#moving">Moving an AVD</a></li>
     <li><a href="#updating">Updating an AVD</a></li>
     <li><a href="#deleting">Deleting an AVD</a></li>
   </ol>
+  <h2>See also</h2>
+  <ol>
+    <li><a href="{@docRoot}guide/developing/building/building-cmdline.html">Building and Running
+from the Command Line</a></li>
+    <li><a href="{@docRoot}guide/developing/devices/emulator.html">Using the Android
+Emulator</a></li>
+  </ol>
   </div>
 </div>
 
@@ -23,7 +36,7 @@
 
 
 
-<h2 id="listingtargets">Listing targets</h2>
+<h2 id="listingtargets">Listing Targets</h2>
 
 <p>To generate a list of system image targets, use this command: </p>
 
@@ -67,7 +80,10 @@
      Skins: HVGA (default), WVGA800, WQVGA432, QVGA, WVGA854, WQVGA400
 </pre>
 
-<h2 id="AVDCmdLine">Creating AVDs</h2> 
+
+
+<h2 id="AVDCmdLine">Creating AVDs</h2>
+
 <p>In addition to creating AVDs with the 
 <a href="{@docRoot}guide/developing/devices/managing-avds-cmdline.html">AVD Manager user interface</a>,
 you can also create them by passing in command line arguments to the <code>android</code> tool.
@@ -92,8 +108,9 @@
 <code>android</code> tool. The target ID is not derived from the system image name, 
 version, or API Level, or other attribute, so you need to run the <code>android list targets</code>
 command to list the target ID of each system image. You should do this <em>before</em> you run
-the <code>android create avd</code> command. See the <a href="{@docRoot}guide/developing/tools/android.html">android</a></p>
-tool documentation for more information on the command line options.  
+the <code>android create avd</code> command. See the <a
+href="{@docRoot}guide/developing/tools/android.html">android</a>
+tool documentation for more information on the command line options.</p>
 
 
 <p>When you've selected the target you want to use and made a note of its ID,
@@ -124,7 +141,45 @@
 from resetting the options. </p>
 
 
-<h3>Default location of AVD files</h3>
+<h3 id="CustomDensity">Customize the device resolution or density</h3>
+
+<p>When testing your application, we recommend that you test your application in several different
+AVDs, using different screen configurations (different combinations of size and density). In
+addition, you should set up the AVDs to run at a physical size that closely matches an actual
+device.</p>
+
+<p>To set up your AVDs for a specific resolution or density, follow these steps:</p>
+
+<ol>
+  <li>Use the <code>create avd</code> command to create a new AVD, specifying
+the <code>--skin</code> option with a value that references either a default
+skin name (such as "WVGA800") or a custom skin resolution (such as 240x432).
+Here's an example:
+     <pre>android create avd -n &lt;name&gt; -t &lt;targetID&gt; --skin WVGA800</pre>
+  </li>
+  <li>To specify a custom density for the skin, answer "yes" when asked whether
+you want to create a custom hardware profile for the new AVD.</li>
+  <li>Continue through the various profile settings until the tool asks you to
+specify "Abstracted LCD density" (<em>hw.lcd.density</em>). Enter an appropriate
+value, such as "120" for a low-density screen, "160" for a medium density screen,
+or "240" for a high-density screen.</li>
+  <li>Set any other hardware options and complete the AVD creation.</li>
+</ol>
+
+<p>In the example above (WVGA medium density), the new AVD will emulate a 5.8"
+WVGA screen.</p>
+
+<p>As an alternative to adjusting the emulator skin configuration, you can use
+the emulator skin's default density and add the <code>-dpi-device</code> option
+to the <a href="{@docRoot}guide/developing/tools/emulator.html">emulator</a> command line when
+starting the AVD. For example:</p>
+
+<pre>emulator -avd WVGA800 -scale 96dpi -dpi-device 160</pre>
+
+
+
+<h3 id="DefaultLocation">Default location of AVD files</h3>
+
 <p>When you create an AVD, the <code>android</code> tool creates a dedicated directory for it
 on your development computer. The directory contains the AVD configuration file,
 the user data image and SD card image (if available), and any other files
@@ -153,7 +208,7 @@
 drive, regardless of the location of the AVD directory. 
 
 
-<h3 id="hardwareopts">Setting Hardware Emulation Options</h3>
+<h3 id="hardwareopts">Setting hardware emulation options</h3>
 
 <p>When you are creating a new AVD that uses a standard Android system image ("Type:
 platform"), the <code>android</code> tool lets you set hardware emulation
diff --git a/docs/html/guide/developing/projects/projects-cmdline.jd b/docs/html/guide/developing/projects/projects-cmdline.jd
index 7c3e40e..90f88fb 100644
--- a/docs/html/guide/developing/projects/projects-cmdline.jd
+++ b/docs/html/guide/developing/projects/projects-cmdline.jd
@@ -9,13 +9,20 @@
 
       <ol>
         <li><a href="#CreatingAProject">Creating an Android Project</a></li>
-
         <li><a href="#UpdatingAProject">Updating a Project</a></li>
-
-        <li><a href="#SettingUpLibraryProject">Setting up a Library Project</a></li>
-
-        <li><a href="#ReferencingLibraryProject">Referencing a Library Project from an
-        Application</a></li>
+        <li><a href="#SettingUpLibraryProject">Setting up a Library Project</a>
+          <ol>
+            <li><a href="#CreatingManifestFile">Creating the manifest file</a></li>
+            <li><a href="#UpdatingLibraryProject">Updating a library project</a></li>
+          </ol>
+        </li>
+        <li><a href="#ReferencingLibraryProject">Referencing a Library Project</a>
+          <ol>
+            <li><a href="#DeclaringLibrary">Declaring library components in the manifest
+file</a></li>
+            <li><a href="#depAppBuild">Building a dependent application</a></li>
+          </ol>
+        </li>
       </ol>
 
       <h2>See also</h2>
@@ -108,7 +115,7 @@
   SDK directory, because this will break the build scripts. (They will need to be manually updated
   to reflect the new SDK location before they will work again.)</p>
 
-  <h2 id="UpdatingAProject">Updating a project</h2>
+  <h2 id="UpdatingAProject">Updating a Project</h2>
 
   <p>If you're upgrading a project from an older version of the Android SDK or want to create a new
   project from existing code, use the <code>android update project</code> command to update the
@@ -142,7 +149,7 @@
 android update project --name MyApp --target 2 --path ./MyAppProject
 </pre>
 
-  <h2 id="SettingUpLibraryProject">Setting up a library project</h2>
+  <h2 id="SettingUpLibraryProject">Setting up a Library Project</h2>
 
   <p>A library project is a standard Android project, so you can create a new one in the same way
   as you would a new application project. Specifically, you can use the <code>android</code> tool
@@ -171,7 +178,7 @@
   applications can use it, you can do so by adding a the <code>android.library=true</code> property
   to the application's <code>default.properties</code> file.</p>
 
-  <h4>Creating the manifest file</h4>
+  <h3 id="CreatingManifestFile">Creating the manifest file</h3>
 
   <p>A library project's manifest file must declare all of the shared components that it includes,
   just as would a standard Android application. For more information, see the documentation for
@@ -191,7 +198,7 @@
 &lt;/manifest&gt;
 </pre>
 
-  <h4>Updating a library project</h4>
+  <h3 id="UpdatingLibraryProject">Updating a library project</h3>
 
   <p>If you want to update the build properties (build target, location) of the library project,
   use this command:</p>
@@ -249,7 +256,7 @@
   that, at build time, libraries are not merged with each other before being merged with the
   application.</p>
 
-  <h3>Declaring library components in the the manifest file</h3>
+  <h3 id="DeclaringLibrary">Declaring library components in the manifest file</h3>
 
   <p>In the manifest file of the application project, you must add declarations of all components
   that the application will use that are imported from a library project. For example, you must
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 46763c2..35acdd7 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -60,14 +60,14 @@
       <li class="toggle-list">
         <div><a href="<?cs var:toroot ?>guide/topics/fundamentals/activities.html">
           <span class="en">Activities</span>
-        </a> <span class="new-child">new!</span></div>
+        </a></div>
         <ul>
           <li><a href="<?cs var:toroot ?>guide/topics/fundamentals/fragments.html">
             <span class="en">Fragments</span>
-          </a> <span class="new">new!</span></li>
+          </a></li>
           <li><a href="<?cs var:toroot ?>guide/topics/fundamentals/loaders.html">
             <span class="en">Loaders</span>
-          </a> <span class="new">new!</span></li>
+          </a></li>
           <li><a href="<?cs var:toroot ?>guide/topics/fundamentals/tasks-and-back-stack.html">
             <span class="en">Tasks and Back Stack</span></a></li>
         </ul>
@@ -98,8 +98,7 @@
       <li class="toggle-list">
         <div><a href="<?cs var:toroot ?>guide/topics/ui/index.html">
             <span class="en">User Interface</span>
-          </a>
-          <span class="new-child">new!</span></div>
+          </a></div>
         <ul>
           <li><a href="<?cs var:toroot ?>guide/topics/ui/declaring-layout.html">
                <span class="en">Declaring Layout</span>
@@ -109,7 +108,7 @@
               </a></li>
           <li><a href="<?cs var:toroot ?>guide/topics/ui/actionbar.html">
                <span class="en">Using the Action Bar</span>
-              </a> <span class="new">new!</span></li>
+              </a></li>
           <li><a href="<?cs var:toroot ?>guide/topics/ui/dialogs.html">
                 <span class="en">Creating Dialogs</span>
               </a></li>
@@ -131,8 +130,7 @@
           </li>
           <li><a href="<?cs var:toroot ?>guide/topics/ui/drag-drop.html">
                 <span class="en">Dragging and Dropping</span>
-              </a> <span class="new">new!</span>
-          </li>
+              </a></li>
           <li><a href="<?cs var:toroot ?>guide/topics/ui/themes.html">
                 <span class="en">Applying Styles and Themes</span>
               </a></li>
@@ -238,8 +236,7 @@
       <li class="toggle-list">
         <div><a href="<?cs var:toroot ?>guide/topics/graphics/index.html">
             <span class="en">Graphics</span>
-          </a>
-          <span class="new-child">new!</span></div>
+          </a></div>
         <ul>
           <li><a href="<?cs var:toroot ?>guide/topics/graphics/2d-graphics.html">
                 <span class="en">2D Graphics</span>
@@ -249,10 +246,10 @@
               </a></li>
           <li><a href="<?cs var:toroot ?>guide/topics/graphics/renderscript.html">
                 <span class="en">3D with Renderscript</span>
-              </a> <span class="new">new!</span></li>
+              </a></li>
           <li><a href="<?cs var:toroot ?>guide/topics/graphics/animation.html">
                 <span class="en">Property Animation</span>
-              </a> <span class="new">new!</span></li>
+              </a></li>
           <li><a href="<?cs var:toroot ?>guide/topics/graphics/view-animation.html">
                 <span class="en">View Animation</span>
               </a></li>
@@ -264,9 +261,7 @@
       <li>
         <a href="<?cs var:toroot ?>guide/topics/clipboard/copy-paste.html">
             <span class="en">Copy and Paste</span>
-        </a>
-        <span class="new">new!</span>
-      </li>
+        </a></li>
   <!--<li class="toggle-list">
         <div><a style="color:gray;">Sensors</a></div>
           <ul>
@@ -299,12 +294,22 @@
             <span class="en">Bluetooth</span>
           </a></li>
       <li><a href="<?cs var:toroot?>guide/topics/nfc/index.html">
-            <span class="en">Near Field Communication</span></a>
-            <span class="new">new!</span></li>
-       <li><a href="<?cs var:toroot?>guide/topics/network/sip.html">
-            <span class="en">Session Initiation Protocol</span></a>
+            <span class="en">Near Field Communication</span>
+          </a></li>
+      <li class="toggle-list">
+          <div><a href="<?cs var:toroot?>guide/topics/usb/index.html">
+            <span class="en">USB</span></a>
             <span class="new">new!</span>
+          </div>
+            <ul>
+              <li><a href="<?cs var:toroot ?>guide/topics/usb/accessory.html">Accessory</a></li>
+              <li><a href="<?cs var:toroot ?>guide/topics/usb/host.html">Host</a></li>
+            </ul>
           </li>
+
+       <li><a href="<?cs var:toroot?>guide/topics/network/sip.html">
+            <span class="en">Session Initiation Protocol</span>
+          </a></li>
       <li class="toggle-list">
         <div><a href="<?cs var:toroot?>guide/topics/search/index.html">
             <span class="en">Search</span>
@@ -347,7 +352,6 @@
                 <a href="<?cs var:toroot ?>guide/topics/testing/what_to_test.html">
                 <span class="en">What To Test</span></a>
               </li>
-
            </ul>
       </li>
     </ul>
@@ -364,7 +368,6 @@
       <li class="toggle-list">
         <div><a href="<?cs var:toroot?>guide/market/billing/index.html">
             <span class="en">In-app Billing</span></a>
-          <span class="new">updated</span>
         </div>
         <ul>
           <li><a href="<?cs var:toroot?>guide/market/billing/billing_about.html">
@@ -654,7 +657,7 @@
           </a></li>
       <li><a href="<?cs var:toroot ?>guide/practices/optimizing-for-3.0.html">
             <span class="en">Optimizing Apps for Android 3.0</span>
-          </a> <span class="new">new!</span></li>
+          </a></li>
       <li class="toggle-list">
         <div><a href="<?cs var:toroot ?>guide/practices/ui_guidelines/index.html">
                <span class="en">UI Guidelines</span>
@@ -700,7 +703,7 @@
       <ul>
       <li><a href="<?cs var:toroot ?>guide/practices/design/accessibility.html">
             <span class="en">Designing for Accessibility</span>
-          </a> <span class="new">new!</span></li>
+          </a></li>
       <li><a href="<?cs var:toroot ?>guide/practices/design/performance.html">
             <span class="en">Designing for Performance</span>
           </a></li>
@@ -754,7 +757,7 @@
           </a></li>
       <li><a href="<?cs var:toroot ?>guide/appendix/media-formats.html">
             <span class="en">Supported Media Formats</span>
-          </a> <span class="new">updated</span></li>
+          </a></li>
       <li><a href="<?cs var:toroot ?>guide/appendix/g-app-intents.html">
             <span class="en">Intents List: Google Apps</span>
           </a></li>
diff --git a/docs/html/guide/market/billing/billing_integrate.jd b/docs/html/guide/market/billing/billing_integrate.jd
index 59344ba..1a1f02a 100755
--- a/docs/html/guide/market/billing/billing_integrate.jd
+++ b/docs/html/guide/market/billing/billing_integrate.jd
@@ -299,7 +299,9 @@
     purchases will show up as actual payouts to your merchant account.</p>
 </ol>
 
-<p class="note"><strong>Note</strong>: Debug log messages are turned off by default in the sample application. You can turn them on by setting the variable <code>DEBUG</code> to <code>true</code> in the <code>Consts.java</code> file.</p>
+<p class="note"><strong>Note</strong>: Debug log messages are turned off by default in the
+sample application. You can turn them on by setting the variable <code>DEBUG</code>
+to <code>true</code> in the <code>Consts.java</code> file.</p>
 
 <h2 id="billing-add-aidl">Adding the AIDL file to your project</h2>
 
@@ -598,7 +600,7 @@
 <code>PURCHASE_INTENT</code> key provides you with a {@link android.app.PendingIntent}, which you
 can use to launch the checkout UI.</p>
 
-<h5>Launching the pending intent</h5>
+<h5>Using the pending intent</h5>
 
 <p>How you use the pending intent depends on which version of Android a device is running. On
 Android 1.6, you must use the pending intent to launch the checkout UI in its own separate task
@@ -649,16 +651,58 @@
 
 <p>A <code>REQUEST_PURCHASE</code> request also triggers two asynchronous responses (broadcast
 intents). First, the Android Market application sends a <code>RESPONSE_CODE</code> broadcast intent,
-which provides error information about the request. Next, if the request was successful, the Android
-Market application sends an <code>IN_APP_NOTIFY</code> broadcast intent. This message contains a
-notification ID, which you can use to retrieve the transaction details for the
-<code>REQUEST_PURCHASE</code> request.</p>
+which provides error information about the request. If the request does not generate an
+error, the <code>RESPONSE_CODE</code> broadcast intent returns <code>RESULT_OK</code>, which
+indicates that the request was successfully sent. (To be clear, a <code>RESULT_OK</code> response
+does not indicate that the requested purchase was successful; it indicates that the request was sent
+successfully to Android Market.)</p>
 
-<p>Keep in mind, the Android Market application also sends an <code>IN_APP_NOTIFY</code> for
-refunds. For more information, see <a
+<p>Next, when the requested transaction changes state (for example, the purchase is successfully
+charged to a credit card or the user cancels the purchase), the Android Market application sends an
+<code>IN_APP_NOTIFY</code> broadcast intent. This message contains a notification ID, which you can
+use to retrieve the transaction details for the <code>REQUEST_PURCHASE</code> request.</p>
+
+<p class="note"><strong>Note:</strong> The Android Market application also sends
+an <code>IN_APP_NOTIFY</code> for refunds. For more information, see <a
 href="{@docRoot}guide/market/billing/billing_overview.html#billing-action-notify">Handling
 IN_APP_NOTIFY messages</a>.</p>
 
+<p>Because the purchase process is not instantaneous and can take several seconds (or more), you
+must assume that a purchase request is pending from the time you receive a <code>RESULT_OK</code>
+message until you receive an <code>IN_APP_NOTIFY</code> message for the transaction. While the
+transaction is pending, the Android Market checkout UI displays an "Authorizing purchase..."
+notification; however, this notification is dismissed after 60 seconds and you should not rely on
+this notification as your primary means of conveying transaction status to users. Instead, we
+recommend that you do the following:</p>
+
+<ul>
+  <li>Add an {@link android.app.Activity} to your application that shows users the status of pending
+and completed in-app purchases.</li>
+  <li>Use a <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">status
+bar notification</a> to keep users informed about the progress of a purchase.</li>
+</ul>
+
+<p>To use these two UI elements, you could invoke a status bar notification with a ticker-text
+message that says "Purchase pending" when your application receives a <code>RESULT_OK</code>
+message. Then, when your application receives an <code>IN_APP_NOTIFY</code> message, you could
+update the notification with a new message that says "Purchase succeeded" or "Purchase failed." When
+a user touches the expanded status bar notification, you could launch the activity that shows the
+status of pending and completed in-app purchases.</p>
+
+<p>If you use some other UI technique to inform users about the state of a pending transaction,
+be sure that your pending status UI does not block your application. For example, you should avoid
+using a hovering progress wheel to convey the status of a pending transaction because a pending
+transaction could last a long time, particularly if a device loses network connectivity and cannot
+receive transaction updates from Android Market.</p>
+
+<p class="caution"><strong>Important:</strong> If a user purchases a managed item, you must prevent
+the user from purchasing the item again while the original transaction is pending. If a user
+attempts to purchase a managed item twice, and the first transaction is still pending, Android
+Market will display an error to the user; however, Android Market will not send an error to your
+application notifying you that the second purchase request was canceled. This might cause your
+application to get stuck in a pending state while it waits for an <code>IN_APP_NOTIFY</code> message
+for the second purchase request.</p>
+
 <h4>Retrieving transaction information for a purchase or refund (GET_PURCHASE_INFORMATION)</h4>
 
 <p>You retrieve transaction information in response to an <code>IN_APP_NOTIFY</code> broadcast
diff --git a/docs/html/guide/topics/admin/device-admin.jd b/docs/html/guide/topics/admin/device-admin.jd
index b86a5f0..7dddd9a 100644
--- a/docs/html/guide/topics/admin/device-admin.jd
+++ b/docs/html/guide/topics/admin/device-admin.jd
@@ -128,6 +128,60 @@
 combination of letters and numbers. They may include symbolic characters.
     </td>
   </tr>
+  
+  <tr>
+    <td>Complex password required</td>
+    <td>Requires that passwords must contain at least a letter, a numerical digit, and a special symbol. Introduced in Android 3.0.
+    </td>
+  </tr>
+  
+<tr> 
+  <td>Minimum letters required in password</td> <td>The minimum number of
+letters required in the password for all admins or a particular one. Introduced in Android 3.0.</td> 
+</tr>
+  
+  
+  <tr> 
+  <td>Minimum lowercase letters required in password</td> 
+  <td>The minimum number of lowercase 
+letters required in the password for all admins or a particular one. Introduced in Android 3.0.</td> 
+</tr>
+  
+  <tr> 
+  <td>Minimum non-letter characters required in password</td> 
+  <td>The minimum number of
+non-letter characters required in the password for all admins or a particular one. Introduced in Android 3.0.</td> 
+</tr>
+  
+<tr> 
+  <td>Minimum numerical digits required in password</td> 
+  <td>The minimum number of numerical digits required in the password for all admins or a particular one. Introduced in Android 3.0.</td> 
+</tr>
+
+<tr> 
+  <td>Minimum symbols required in password</td> 
+  <td>The minimum number of symbols required in the password for all admins or a particular one. Introduced in Android 3.0.</td> 
+</tr>
+
+<tr> 
+  <td>Minimum uppercase letters required in password</td> 
+  <td>The minimum number of uppercase letters required in the password for all admins or a particular one. Introduced in Android 3.0.</td> 
+</tr>
+
+<tr> 
+  <td>Password expiration timeout</td> 
+  <td>When the password will expire, expressed as a delta in milliseconds from when a device admin sets the expiration timeout. Introduced in Android 3.0.</td> 
+</tr>
+
+<tr> 
+  <td>Password history restriction</td> 
+  <td>This policy prevents users from reusing the last <em>n</em> unique passwords.
+ This policy is typically used in conjunction with
+{@link android.app.admin.DevicePolicyManager#setPasswordExpirationTimeout(android.content.ComponentName,long) setPasswordExpirationTimeout()}, which forces
+users to update their passwords after a specified amount of time has elapsed.
+Introduced in Android 3.0.</td> 
+</tr>
+  
   <tr>
     <td>Maximum failed password attempts </td>
     <td>Specifies how many times a user can enter the wrong password before the
@@ -141,6 +195,12 @@
 pressed a button before the device locks the screen. When this happens, users
 need to enter their PIN or passwords again before they can use their devices and
 access data.  The value can be between 1 and 60 minutes.</td> </tr>
+
+<tr> 
+<td>Require storage encryption</td> 
+<td>Specifies that the storage area should be encrypted, if the device supports it. 
+Introduced in Android 3.0.</td> </tr>
+
 </table>
 
 <h4>Other features</h4>
@@ -172,18 +232,28 @@
 to do the following:</p>
 <ul>
   <li>Set password quality.</li>
-  <li>Specify the minimum length for the user's password.</li>
+  <li>Specify requirements for the user's password, such as minimum length, the minimum number of
+  numeric characters it must contain, and so on.</li>
   <li>Set the password. If the password does not conform to the specified
 policies, the system  returns an error.</li>
   <li>Set how many failed password attempts can occur before the device is wiped
 (that is, restored to factory settings).</li>
+<li>Set how long from now the password will expire.</li>
+<li>Set the password history length (<em>length</em> refers to number of old passwords stored in the history). 
+This prevents users from reusing 
+one of the last <em>n</em> passwords they previously used.</li>
+<li>Specify that the storage area should be encrypted, if the device supports it.</li>
   <li>Set the maximum amount of inactive time that can elapse before the device
 locks.</li>
   <li>Make the device lock immediately.</li>
   <li>Wipe the device's data (that is, restore factory settings).</li>
+  
 </ul>
 
+
+
 <img src="{@docRoot}images/admin/device-admin-app.png"/>
+
 <p class="img-caption"><strong>Figure 1.</strong> Screenshot of the Sample Application</p>
 
 
@@ -469,7 +539,13 @@
 other symbol) characters.</dd>
   <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_NUMERIC}</dt><dd>The user must enter a   password
 containing at least numeric characters.</dd>
-  <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_SOMETHING}</dt><dd>The policy requires some kind
+<dt>{@link
+android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_COMPLEX}</dt><dd>The user
+must have entered a password containing at least a letter, a numerical digit and
+a special symbol.</dd> 
+<dt>{@link
+android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_SOMETHING}</dt><dd>The
+policy requires some kind
 of password, but doesn't care what it is.</dd>
   <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}</dt><dd>
   The policy has no requirements   for the password. </dd>
@@ -482,6 +558,36 @@
 mDPM.setPasswordQuality(mDeviceAdminSample, DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC);
 </pre>
 
+<h5>Set password content requirements</h5>
+
+<p>Beginning with Android 3.0, the {@link android.app.admin.DevicePolicyManager} class
+includes methods that let you fine-tune the contents of the password. For
+example, you could set a policy that states that passwords must contain at least
+<em>n</em> uppercase letters. Here are the methods for fine-tuning a password's
+contents:</p>
+<ul>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumLetters(android.content.ComponentName,int) setPasswordMinimumLetters()}</li> 
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumLowerCase(android.content.ComponentName,int) setPasswordMinimumLowerCase()}</li>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumUpperCase(android.content.ComponentName,int) setPasswordMinimumUpperCase()}</li>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumNonLetter(android.content.ComponentName,int) setPasswordMinimumNonLetter()}</li>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumNumeric(android.content.ComponentName,int) setPasswordMinimumNumeric()}</li>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumSymbols(android.content.ComponentName,int) setPasswordMinimumSymbols()}</li>
+</ul>
+<p>For example, this snippet states that the password must have at least 2 uppercase letters:</p>
+<pre>
+DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+int pwMinUppercase = 2;
+...
+mDPM.setPasswordMinimumUpperCase(mDeviceAdminSample, pwMinUppercase);</pre>
+
+
 <h5>Set the minimum password length</h5>
 <p>You can specify that a password must be at least the specified minimum
 length. For example:</p>
@@ -501,7 +607,86 @@
  ...
 mDPM.setMaximumFailedPasswordsForWipe(mDeviceAdminSample, maxFailedPw);</pre>
 
-<h4 id="lock">Set  device lock</h4>
+<h5 id="expiration">Set password expiration timeout</h5>
+<p>Beginning with Android 3.0, you can use the 
+{@link android.app.admin.DevicePolicyManager#setPasswordExpirationTimeout(android.content.ComponentName,long) setPasswordExpirationTimeout()} 
+method to set when a password will expire, expressed as a delta in milliseconds from when a device admin sets the expiration timeout. For example:</p>
+
+<pre>DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+long pwExpiration;
+...
+mDPM.setPasswordExpirationTimeout(mDeviceAdminSample, pwExpiration);
+</pre>
+
+<p>From the <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/
+DeviceAdminSample.html"> Device Administration API sample</a>, here is the code
+that updates the password expiration status:</p>
+
+<pre>
+DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+private TextView mPasswordExpirationStatus;
+...
+void updatePasswordExpirationStatus() {
+    boolean active = mDPM.isAdminActive(mDeviceAdminSample);
+    String statusText;
+    if (active) {
+        long now = System.currentTimeMillis();
+        // Query the DevicePolicyManager twice - first for the expiration values
+        // set by the sample app, and later, for the system values (which may be different
+        // if there is another administrator active.)
+        long expirationDate = mDPM.getPasswordExpiration(mDeviceAdminSample);
+        long mSecUntilExpiration = expirationDate - now;
+        if (mSecUntilExpiration &gt;= 0) {
+            statusText = &quot;Expiration in &quot; + countdownString(mSecUntilExpiration);
+        } else {
+            statusText = &quot;Expired &quot; + countdownString(-mSecUntilExpiration) + &quot; ago&quot;;
+        }
+
+        // expirationTimeout is the cycle time between required password refresh
+        long expirationTimeout = mDPM.getPasswordExpirationTimeout(mDeviceAdminSample);
+        statusText += &quot; / timeout period &quot; + countdownString(expirationTimeout);
+
+        // Now report the aggregate (global) expiration time
+        statusText += &quot; / Aggregate &quot;;
+        expirationDate = mDPM.getPasswordExpiration(null);
+        mSecUntilExpiration = expirationDate - now;
+        if (mSecUntilExpiration &gt;= 0) {
+            statusText += &quot;expiration in &quot; + countdownString(mSecUntilExpiration);
+        } else {
+            statusText += &quot;expired &quot; + countdownString(-mSecUntilExpiration) + &quot; ago&quot;;
+        }
+    } else {
+        statusText = &quot;&lt;inactive&gt;&quot;;
+    }
+    mPasswordExpirationStatus.setText(statusText);</pre>
+    
+<h5 id="history">Restrict password based on history</h5>
+
+<p>Beginning with Android 3.0, you can use the 
+{@link android.app.admin.DevicePolicyManager#setPasswordHistoryLength(android.content.ComponentName,int) setPasswordHistoryLength()} 
+method to limit users'
+ability to reuse old passwords. This method takes a <em>length</em>
+parameter, which specifies how many old
+passwords are stored. When this policy is active, users cannot enter a new
+password that matches the last <em>n</em> passwords. This prevents
+users from using the same password over and over. This policy is typically used
+in conjunction with 
+{@link android.app.admin.DevicePolicyManager#setPasswordExpirationTimeout(android.content.ComponentName,long) setPasswordExpirationTimeout()},
+which forces users
+to update their passwords after a specified amount of time has elapsed. </p>
+
+<p>For example, this snippet prohibits users from reusing any of their last 5 passwords:</p>
+
+<pre>DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+int pwHistoryLength = 5;
+...
+mDPM.setPasswordHistoryLength(mDeviceAdminSample, pwHistoryLength);
+</pre>
+
+<h4 id="lock">Set device lock</h4>
 <p>You can set the maximum period of user inactivity that can occur before the
 device locks. For example:</p>
 <pre>
@@ -516,6 +701,8 @@
 DevicePolicyManager mDPM;
 mDPM.lockNow();</pre>
 
+
+
 <h4 id="wipe">Perform data wipe</h4>
 
 <p>You can use the {@link android.app.admin.DevicePolicyManager} method
@@ -530,3 +717,20 @@
 mDPM.wipeData(0);</pre>
 <p>The {@link android.app.admin.DevicePolicyManager#wipeData wipeData()} method takes as its parameter a bit mask of
 additional options. Currently the value must be 0. </p>
+
+<h4 id=storage">Storage encryption</h4>
+<p>Beginning with Android 3.0, you can use the 
+{@link android.app.admin.DevicePolicyManager#setStorageEncryption(android.content.ComponentName,boolean) setStorageEncryption()} 
+method to set a policy requiring encryption of the storage area, where supported.</p>
+
+<p>For example:</p>
+
+<pre>
+DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+...
+mDPM.setStorageEncryption(mDeviceAdminSample, true);
+</pre>
+<p>
+See the <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.html"> Device Administration API sample</a> for a complete
+example of how to enable storage encryption.</p>
diff --git a/docs/html/guide/topics/graphics/animation.jd b/docs/html/guide/topics/graphics/animation.jd
index 3b1716c..e10ab3e 100644
--- a/docs/html/guide/topics/graphics/animation.jd
+++ b/docs/html/guide/topics/graphics/animation.jd
@@ -903,7 +903,7 @@
     <code>"floatType"</code> unless you specify something else or if the <code>valuesFrom</code>
     and <code>valuesTo</code> values are colors.</dd>
 
-    <dt><code>android:startDelay</code></dt>
+    <dt><code>android:startOffset</code></dt>
 
     <dd>The delay, in milliseconds, before the animation begins playing (after calling {@link
     android.animation.ValueAnimator#start start()}).</dd>
diff --git a/docs/html/guide/topics/resources/menu-resource.jd b/docs/html/guide/topics/resources/menu-resource.jd
index 5c1eed0..5b90ce2 100644
--- a/docs/html/guide/topics/resources/menu-resource.jd
+++ b/docs/html/guide/topics/resources/menu-resource.jd
@@ -49,14 +49,14 @@
           android:alphabeticShortcut="<em>string</em>"
           android:numericShortcut="<em>string</em>"
           android:checkable=["true" | "false"]
-          android:visible=["visible" | "invisible" | "gone"]
-          android:enabled=["enabled" | "disabled"]
+          android:visible=["true" | "false"]
+          android:enabled=["true" | "false"]
           android:menuCategory=["container" | "system" | "secondary" | "alternative"]
           android:orderInCategory="<em>integer</em>" /&gt;
     &lt;<a href="#group-element">group</a> android:id="@[+][<em>package</em>:]id/<em>resource name</em>"
            android:checkableBehavior=["none" | "all" | "single"]
-           android:visible=["visible" | "invisible" | "gone"]
-           android:enabled=["enabled" | "disabled"]
+           android:visible=["true" | "false"]
+           android:enabled=["true" | "false"]
            android:menuCategory=["container" | "system" | "secondary" | "alternative"]
            android:orderInCategory="<em>integer</em>" &gt;
         &lt;<a href="#item-element">item</a> /&gt;
diff --git a/docs/html/guide/topics/usb/accessory.jd b/docs/html/guide/topics/usb/accessory.jd
new file mode 100644
index 0000000..b0f4881
--- /dev/null
+++ b/docs/html/guide/topics/usb/accessory.jd
@@ -0,0 +1,461 @@
+page.title=USB Accessory
+@jd:body
+
+  <div id="qv-wrapper">
+    <div id="qv">
+      <h2>In this document</h2>
+
+      <ol>
+        <li>
+          <a href="#choosing">Choosing the Right USB Accessory APIs</a>
+
+          <ol>
+            <li><a href="#installing">Installing the Google APIs add-on library</a></li>
+          </ol>
+        </li>
+
+        <li>
+          <a href="#api">API Overview</a>
+
+          <ol>
+            <li><a href="#usage">Usage differences between the add-on library and the platform
+            APIs</a></li>
+          </ol>
+        </li>
+
+        <li><a href="#manifest">Android Manifest Requirements</a></li>
+
+        <li>
+          <a href="#working-a">Working with accessories</a>
+
+          <ol>
+            <li><a href="#discovering-a">Discovering an accessory</a></li>
+
+            <li><a href="#permission-a">Obtaining permission to communicate with an
+            accessory</a></li>
+
+            <li><a href="#communicating-a">Communicating with an accessory</a></li>
+
+            <li><a href="#terminating-a">Terminating communication with an accessory</a></li>
+          </ol>
+        </li>
+      </ol>
+
+      <h2>See also</h2>
+
+      <ol>
+        <li><a href="http://accessories.android.com/demokit">Android USB Accessory Development
+        Kit</a></li>
+      </ol>
+    </div>
+  </div>
+
+  <p>USB accessory mode allows users to connect
+  USB host hardware specifically designed for Android-powered devices. The accessories must adhere
+  to the Android accessory protocol outlined in the <a href=
+  "http://accessories.android.com/demokit">Android Accessory Development Kit</a> documentation.
+  This allows Android-powered devices that cannot act as a USB host to still interact with USB
+  hardware. When an Android-powered device is in USB accessory mode, the attached Android USB
+  accessory acts as the host, provides power to the USB bus, and enumerates connected devices.
+  Android 3.1 (API level 12) supports USB accessory mode and the feature is also backported to
+  Android 2.3.4 (API level 10) to enable support for a broader range of devices.</p>
+
+  <h2 id="choosing">Choosing the Right USB Accessory APIs</h2>
+
+  <p>Although the USB accessory APIs were introduced to the platform in Android 3.1, they are also
+  available in Android 2.3.4 using the Google APIs add-on library. Because these APIs were
+  backported using an external library, there are two packages that you can import to support USB
+  accessory mode. Depending on what Android-powered devices you want to support, you might have to
+  use one over the other:</p>
+
+  <ul>
+    <li><code>com.android.future.usb</code>: To support USB accessory mode in Android 2.3.4, the
+    <a href="http://code.google.com/android/add-ons/google-apis/index.html">Google APIs add-on
+    library</a> includes the backported USB accessory APIs and they are contained in this
+    namespace. Android 3.1 also supports importing and calling the classes within this namespace to
+    support applications written with the add-on library. This add-on library is a thin wrapper
+    around the {@link android.hardware.usb} accessory APIs and does not support USB host mode. If
+    you want to support the widest range of devices that support USB accessory mode, use the add-on
+    library and import this package. It is important to note that not all Android 2.3.4 devices are
+    required to support the USB accessory feature. Each individual device manufacturer decides
+    whether or not to support this capability, which is why you must declare it in your manifest
+    file.</li>
+
+    <li>{@link android.hardware.usb}: This namespace contains the classes that support USB
+    accessory mode in Android 3.1. This package is included as part of the framework APIs, so
+    Android 3.1 supports USB accessory mode without the use of an add-on library. Use this package
+    if you only care about Android 3.1 or newer devices that have hardware support for USB
+    accessory mode, which you can declare in your manifest file.</li>
+  </ul>
+
+  <h3 id="installing">Installing the Google APIs add-on library</h3>
+
+  <p>If you want to install the add-on, you can do so by installing the Google APIs Android API 10
+  package with the SDK Manager. See <a href=
+  "http://code.google.com/android/add-ons/google-apis/installing.html">Installing the Google APIs
+  Add-on</a> for more information on installing the add-on library.</p>
+
+  <h2 id="api">API Overview</h2>
+
+  <p>Because the add-on library is a wrapper for the framework APIs, the classes that support the
+  USB accessory feature are similar. You can use the reference documentation for the {@link
+  android.hardware.usb} even if you are using the add-on library.</p>
+
+  <p class="note"><strong>Note:</strong> There is, however, a minor <a href="#usage">usage
+  difference</a> between the add-on library and framework APIs that you should be aware of.</p>
+
+  <p>The following table describes the classes that support the USB accessory APIs:</p>
+
+  <table>
+    <tr>
+      <th>Class</th>
+
+      <th>Description</th>
+    </tr>
+
+    <tr>
+      <td>{@link android.hardware.usb.UsbManager}</td>
+
+      <td>Allows you to enumerate and communicate with connected USB accessories.</td>
+    </tr>
+
+    <tr>
+      <td>{@link android.hardware.usb.UsbAccessory}</td>
+
+      <td>Represents a USB accessory and contains methods to access its identifying
+      information.</td>
+    </tr>
+  </table>
+
+  <h3 id="usage">Usage differences between the add-on library and platform APIs</h3>
+
+  <p>There are two usage differences between using the Google APIs add-on library and the platform
+  APIs.</p>
+
+  <p>If you are using the add-on library, you must obtain the {@link
+  android.hardware.usb.UsbManager} object in the following manner:</p>
+  <pre>
+UsbManager manager = UsbManager.getInstance(this);
+</pre>
+
+  <p>If you are not using the add-on library, you must obtain the {@link
+  android.hardware.usb.UsbManager} object in the following manner:</p>
+  <pre>
+UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
+</pre>
+
+  <p>When you filter for a connected accessory with an intent filter, the {@link
+  android.hardware.usb.UsbAccessory} object is contained inside the intent that is passed to your
+  application. If you are using the add-on library, you must obtain the {@link
+  android.hardware.usb.UsbAccessory} object in the following manner:</p>
+  <pre>
+UsbAccessory accessory = UsbManager.getAccessory(intent);
+</pre>
+
+  <p>If you are not using the add-on library, you must obtain the {@link
+  android.hardware.usb.UsbAccessory} object in the following manner:</p>
+  <pre>
+UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+</pre>
+
+  <h2 id="manifest">Android Manifest requirements</h2>
+
+  <p>The following list describes what you need to add to your application's manifest file before
+  working with the USB accesory APIs. The <a href="#manifest-example">manifest and resource file
+  examples</a> show how to declare these items:</p>
+
+  <ul>
+    <li>Because not all Android-powered devices are guaranteed to support the USB accessory APIs,
+    include a <code>&lt;uses-feature&gt;</code> element that declares that your application uses
+    the <code>android.hardware.usb.accessory</code> feature.</li>
+
+    <li>If you are using the <a href="addon">add-on library</a>, add the
+    <code>&lt;uses-library&gt;</code> element specifying
+    <code>com.android.future.usb.accessory</code> for the library.</li>
+
+    <li>Set the minimum SDK of the application to API Level 10 if you are using the add-on library
+    or 12 if you are using the {@link android.hardware.usb} package.</li>
+
+    <li>
+      <p>If you want your application to be notified of an attached USB accessory, specify an
+      <code>&lt;intent-filter&gt;</code> and <code>&lt;meta-data&gt;</code> element pair for the
+      <code>android.hardware.usb.action.USB_ACCESSORY_ATTACHED</code> intent in your main activity.
+      The <code>&lt;meta-data&gt;</code> element points to an external XML resource file that
+      declares identifying information about the accessory that you want to detect.</p>
+
+      <p>In the XML resource file, declare <code>&lt;usb-accessory&gt;</code> elements for the
+      accessories that you want to filter. Each <code>&lt;usb-accessory&gt;</code> can have the
+      following attributes:</p>
+
+      <ul>
+        <li><code>manufacturer</code></li>
+
+        <li><code>model</code></li>
+
+        <li><code>version</code></li>
+      </ul>
+
+      <p>Save the resource file in the <code>res/xml/</code> directory. The resource file name
+      (without the .xml extension) must be the same as the one you specified in the
+      <code>&lt;meta-data&gt;</code> element. The format for the XML resource file is also shown in
+      the <a href="#example">example</a> below.</p>
+    </li>
+  </ul>
+
+  <h3 id="manifest-example">Manifest and resource file examples</h3>
+
+  <p>The following example shows a sample manifest and its corresponding resource file:</p>
+  <pre>
+&lt;manifest ...&gt;
+    &lt;uses-feature android:name="android.hardware.usb.accessory" /&gt;
+    <!-- version must be either 10 or 12 -->
+    &lt;uses-sdk android:minSdkVersion="&lt;<em>version</em>&gt;" /&gt;
+    ...
+    &lt;application&gt;
+      &lt;uses-library android:name="com.android.future.usb.accessory" /&gt;
+        &lt;activity ...&gt;
+            ...
+            &lt;intent-filter&gt;
+                &lt;action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /&gt;
+            &lt;/intent-filter&gt;
+
+            &lt;meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
+                android:resource="@xml/accessory_filter" /&gt;
+        &lt;/activity&gt;
+    &lt;/application&gt;
+&lt;/manifest&gt;
+</pre>
+
+  <p>In this case, the following resource file should be saved in
+  <code>res/xml/accessory_filter.xml</code> and specifies that any accessory that has the
+  corresponding model, manufacturer, and version should be filtered. The accessory sends these
+  attributes the Android-powered device:</p>
+  <pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+
+&lt;resources&gt;
+    &lt;usb-accessory model="DemoKit" manufacturer="Google" version="1.0"/&gt;
+&lt;/resources&gt;
+</pre>
+
+  <h2 id="working-a">Working with Accessories</h2>
+
+  <p>When users connect USB accessories to an Android-powered device, the Android system can
+  determine whether your application is interested in the connected accessory. If so, you can set
+  up communication with the accessory if desired. To do this, your application has to:</p>
+
+  <ol>
+    <li>Discover connected accessories by using an intent filter that filters for accessory
+    attached events or by enumerating connected accessories and finding the appropriate one.</li>
+
+    <li>Ask the user for permission to communicate with the accessory, if not already
+    obtained.</li>
+
+    <li>Communicate with the accessory by reading and writing data on the appropriate interface
+    endpoints.</li>
+  </ol>
+
+  <h3 id="discovering-a">Discovering an accessory</h3>
+
+  <p>Your application can discover accessories by either using an intent filter to be notified when
+  the user connects an accessory or by enumerating accessories that are already connected. Using an
+  intent filter is useful if you want to be able to have your application automatically detect a
+  desired accessory. Enumerating connected accessories is useful if you want to get a list of all
+  connected accessories or if your application did not filter for an intent.</p>
+
+  <h4 id="discover-a-intent">Using an intent filter</h4>
+
+  <p>To have your application discover a particular USB accessory, you can specify an intent filter
+  to filter for the <code>android.hardware.usb.action.USB_ACCESSORY_ATTACHED</code> intent. Along
+  with this intent filter, you need to specify a resource file that specifies properties of the USB
+  accessory, such as manufacturer, model, and version. When users connect an accessory that matches
+  your accessory filter,</p>
+
+  <p>The following example shows how to declare the intent filter:</p>
+  <pre>
+&lt;activity ...&gt;
+    ...
+    &lt;intent-filter&gt;
+        &lt;action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /&gt;
+    &lt;/intent-filter&gt;
+
+    &lt;meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
+        android:resource="@xml/accessory_filter" /&gt;
+&lt;/activity&gt;
+</pre>
+
+  <p>The following example shows how to declare the corresponding resource file that specifies the
+  USB accessories that you're interested in:</p>
+  <pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+
+&lt;resources&gt;
+    &lt;usb-accessory manufacturer="Google, Inc." model="DemoKit" version="1.0" /&gt;
+&lt;/resources&gt;
+</pre>
+
+  <p>In your activity, you can obtain the {@link android.hardware.usb.UsbAccessory} that represents
+  the attached accessory from the intent like this (with the add-on library):</p>
+  <pre>
+UsbAccessory accessory = UsbManager.getAccessory(intent);
+</pre>
+
+  <p>or like this (with the platform APIs):</p>
+  <pre>
+UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+</pre>
+
+  <h4 id="discover-a-enumerate">Enumerating accessories</h4>
+
+  <p>You can have your application enumerate accesories that have identified themselves while your
+  application is running.</p>
+
+  <p>Use the {@link android.hardware.usb.UsbManager#getAccessoryList() getAccessoryList()} method
+  to get an array all the USB accessories that are connected:</p>
+  <pre>
+UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
+UsbAccessory[] accessoryList = manager.getAcccessoryList();
+</pre>
+
+  <p class="note"><strong>Note:</strong> Currently, only one connected accessory is supported at
+  one time, but the API is designed to support multiple accessories in the future.</p>
+
+  <h3 id="permission-a">Obtaining permission to communicate with an accessory</h3>
+
+  <p>Before communicating with the USB accessory, your applicaton must have permission from your
+  users.</p>
+
+  <p class="note"><strong>Note:</strong> If your application <a href="#using-intents">uses an
+  intent filter</a> to discover accessories as they're connected, it automatically receives
+  permission if the user allows your application to handle the intent. If not, you must request
+  permission explicitly in your application before connecting to the accessory.</p>
+
+  <p>Explicitly asking for permission might be neccessary in some situations such as when your
+  application enumerates accessories that are already connected and then wants to communicate with
+  one. You must check for permission to access an accessory before trying to communicate with it.
+  If not, you will receive a runtime error if the user denied permission to access the
+  accessory.</p>
+
+  <p>To explicitly obtain permission, first create a broadcast receiver. This receiver listens for
+  the intent that gets broadcast when you call {@link
+  android.hardware.usb.UsbManager#requestPermission requestPermission()}. The call to {@link
+  android.hardware.usb.UsbManager#requestPermission requestPermission()} displays a dialog to the
+  user asking for permission to connect to the accessory. The following sample code shows how to
+  create the broadcast receiver:</p>
+  <pre>
+private static final String ACTION_USB_PERMISSION =
+    "com.android.example.USB_PERMISSION";
+private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
+ 
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        if (ACTION_USB_PERMISSION.equals(action)) {
+            synchronized (this) {
+                UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+
+                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+                    if(accessory != null){
+                        //call method to set up accessory communication
+                    }
+                }
+                else {
+                    Log.d(TAG, "permission denied for accessory " + accessory);
+                }
+            }
+        }
+    }
+};
+</pre>
+
+  <p>To register the broadcast receiver, put this in your <code>onCreate()</code> method in your
+  activity:</p>
+  <pre>
+UsbManager mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
+private static final String ACTION_USB_PERMISSION =
+    "com.android.example.USB_PERMISSION";
+...
+mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
+IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
+registerReceiver(mUsbReceiver, filter);
+</pre>
+
+  <p>To display the dialog that asks users for permission to connect to the accessory, call the
+  {@link android.hardware.usb.UsbManager#requestPermission requestPermission()} method:</p>
+  <pre>
+UsbAccessory accessory;
+...
+mUsbManager.requestPermission(accessory, mPermissionIntent);
+</pre>
+
+  <p>When users reply to the dialog, your broadcast receiver receives the intent that contains the
+  {@link android.hardware.usb.UsbManager#EXTRA_PERMISSION_GRANTED} extra, which is a boolean
+  representing the answer. Check this extra for a value of true before connecting to the
+  accessory.</p>
+
+  <h3 id="communicating-a">Communicating with an accessory</h3>
+
+  <p>You can communicate with the accessory by using the {@link android.hardware.usb.UsbManager} to
+  obtain a file descriptor that you can set up input and output streams to read and write data to
+  descriptor. The streams represent the accessory's input and output bulk endpoints. You should set
+  up the communication between the device and accessory in another thread, so you don't lock the
+  main UI thread. The following example shows how to open an accessory to communicate with:</p>
+  <pre>
+UsbAccessory mAccessory;
+ParcelFileDescriptor mFileDescriptor;
+FileInputStream mInputStream;
+FileOutputStream mOutputStream;
+
+...
+
+private void openAccessory() {
+    Log.d(TAG, "openAccessory: " + accessory);
+    mFileDescriptor = mUsbManager.openAccessory(mAccessory);
+    if (mFileDescriptor != null) {
+        FileDescriptor fd = mFileDescriptor.getFileDescriptor();
+        mInputStream = new FileInputStream(fd);
+        mOutputStream = new FileOutputStream(fd);
+        Thread thread = new Thread(null, this, "AccessoryThread");
+        thread.start();
+    }
+}
+</pre>
+
+  <p>In the thread's <code>run()</code> method, you can read and write to the accessory by using
+  the {@link java.io.FileInputStream} or {@link java.io.FileOutputStream} objects. When reading
+  data from an accessory with a {@link java.io.FileInputStream} object, ensure that the buffer that
+  you use is big enough to store the USB packet data. The Android accessory protocol supports
+  packet buffers up to 16384 bytes, so you can choose to always declare your buffer to be of this
+  size for simplicity.</p>
+
+  <p class="note"><strong>Note:</strong> At a lower level, the packets are 64 bytes for USB
+  full-speed accessories and 512 bytes for USB high-speed accessories. The Android accessory
+  protocol bundles the packets together for both speeds into one logical packet for simplicity.</p>
+
+  <p>For more information about using threads in Android, see <a href=
+  "{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes and
+  Threads</a>.</p>
+
+  <h3 id="terminating-a">Terminating communication with an accessory</h3>
+
+  <p>When you are done communicating with an accessory or if the accessory was detached, close the
+  file descriptor that you opened by calling {@link android.os.ParcelFileDescriptor#close close()}.
+  To listen for detached events, create a broadcast receiver like below:</p>
+  <pre>
+BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction(); 
+
+        if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
+            UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+            if (accessory != null) {
+                // call your method that cleans up and closes communication with the accessory
+            }
+        }
+    }
+};
+</pre>
+
+  <p>Creating the broadcast receiver within the application, and not the manifest, allows your
+  application to only handle detached events while it is running. This way, detached events are
+  only sent to the application that is currently running and not broadcast to all applications.</p>
+
diff --git a/docs/html/guide/topics/usb/host.jd b/docs/html/guide/topics/usb/host.jd
new file mode 100644
index 0000000..942708d
--- /dev/null
+++ b/docs/html/guide/topics/usb/host.jd
@@ -0,0 +1,443 @@
+page.title=USB Host
+@jd:body
+
+  <div id="qv-wrapper">
+    <div id="qv">
+      <h2>In this document</h2>
+
+      <ol>
+        <li><a href="#api">API Overview</a></li>
+
+        <li><a href="#usage">Android Manifest Requirements</a></li>
+
+        <li>
+          <a href="#working-d">Working with devices</a>
+
+          <ol>
+            <li><a href="#discovering-d">Discovering a device</a></li>
+
+            <li><a href="#permission-d">Obtaining permission to communicate with a device</a></li>
+
+            <li><a href="#communicating-d">Communicating with a device</a></li>
+
+            <li><a href="#terminating-d">Terminating communication with a device</a></li>
+          </ol>
+        </li>
+      </ol>
+
+      <h2>Related Samples</h2>
+
+      <ol>
+        <li><a href="{@docRoot}resources/samples/USB/AdbTest/index.html">AdbTest</a></li>
+
+        <li><a href=
+        "{@docRoot}resources/samples/USB/MissileLauncher/index.html">MissleLauncher</a></li>
+      </ol>
+    </div>
+  </div>
+
+  <p>When your Android-powered device is in USB host mode, it acts as the USB host, powers the bus,
+  and enumerates connected USB devices. USB host mode is supported in Android 3.1 and higher.</p>
+
+  <h2 id="api">API Overview</h2>
+
+  <p>Before you begin, it is important to understand the classes that you need to work with. The
+  following table describes the USB host APIs in the {@link android.hardware.usb} package.</p>
+
+  <p class="table-caption"><strong>Table 1.</strong> USB Host APIs</p>
+
+  <table>
+    <tr>
+      <th>Class</th>
+
+      <th>Description</th>
+    </tr>
+
+    <tr>
+      <td>{@link android.hardware.usb.UsbManager}</td>
+
+      <td>Allows you to enumerate and communicate with connected USB devices.</td>
+    </tr>
+
+    <tr>
+      <td>{@link android.hardware.usb.UsbDevice}</td>
+
+      <td>Represents a connected USB device and contains methods to access its identifying
+      information, interfaces, and endpoints.</td>
+    </tr>
+
+    <tr>
+      <td>{@link android.hardware.usb.UsbInterface}</td>
+
+      <td>Represents an interface of a USB device, which defines a set of functionality for the
+      device. A device can have one or more interfaces on which to communicate on.</td>
+    </tr>
+
+    <tr>
+      <td>{@link android.hardware.usb.UsbEndpoint}</td>
+
+      <td>Represents an interface endpoint, which is a communication channel for this interface. An
+      interface can have one or more endpoints, and usually has input and output endpoints for
+      two-way communication with the device.</td>
+    </tr>
+
+    <tr>
+      <td>{@link android.hardware.usb.UsbDeviceConnection}</td>
+
+      <td>Represents a connection to the device, which transfers data on endpoints. This class
+      allows you to send data back and forth sychronously or asynchronously.</td>
+    </tr>
+
+    <tr>
+      <td>{@link android.hardware.usb.UsbRequest}</td>
+
+      <td>Represents an asynchronous request to communicate with a device through a {@link
+      android.hardware.usb.UsbDeviceConnection}.</td>
+    </tr>
+
+    <tr>
+      <td>{@link android.hardware.usb.UsbConstants}</td>
+
+      <td>Defines USB constants that correspond to definitions in linux/usb/ch9.h of the Linux
+      kernel.</td>
+    </tr>
+  </table>
+
+  <p>In most situations, you need to use all of these classes ({@link
+  android.hardware.usb.UsbRequest} is only required if you are doing asynchronous communication)
+  when communicating with a USB device. In general, you obtain a {@link
+  android.hardware.usb.UsbManager} to retrieve the desired {@link android.hardware.usb.UsbDevice}.
+  When you have the device, you need to find the appropriate {@link
+  android.hardware.usb.UsbInterface} and the {@link android.hardware.usb.UsbEndpoint} of that
+  interface to communicate on. Once you obtain the correct endpoint, open a {@link
+  android.hardware.usb.UsbDeviceConnection} to communicate with the USB device.</p>
+
+  <h2 id="manifest">Android Manifest Requirements</h2>
+
+  <p>The following list describes what you need to add to your application's manifest file before
+  working with the USB host APIs:</p>
+
+  <ul>
+    <li>Because not all Android-powered devices are guaranteed to support the USB host APIs,
+    include a <code>&lt;uses-feature&gt;</code> element that declares that your application uses
+    the <code>android.hardware.usb.host</code> feature.</li>
+
+    <li>Set the minimum SDK of the application to API Level 12 or higher. The USB host APIs are not
+    present on earlier API levels.</li>
+
+    <li>If you want your application to be notified of an attached USB device, specify an
+    <code>&lt;intent-filter&gt;</code> and <code>&lt;meta-data&gt;</code> element pair for the
+    <code>android.hardware.usb.action.USB_DEVICE_ATTACHED</code> intent in your main activity. The
+    <code>&lt;meta-data&gt;</code> element points to an external XML resource file that declares
+    identifying information about the device that you want to detect.
+
+      <p>In the XML resource file, declare <code>&lt;usb-device&gt;</code> elements for the USB
+      devices that you want to filter. The following list describes the attributes of
+      <code>&lt;usb-device&gt;</code>. In general, use vendor and product ID if you want to filter
+      for a specific device and use class, subclass, and protocol if you want to filter for a group
+      of USB devices, such as mass storage devices or digital cameras.</p>
+
+      <ul>
+        <li><code>vendor-id</code></li>
+
+        <li><code>product-id</code></li>
+
+        <li><code>class</code></li>
+
+        <li><code>subclass</code></li>
+
+        <li><code>protocol</code> (device or interface)</li>
+      </ul>
+
+      <p>Save the resource file in the <code>res/xml/</code> directory. The resource file name
+      (without the .xml extension) must be the same as the one you specified in the
+      <code>&lt;meta-data&gt;</code> element. The format for the XML resource file is in the
+      <a href="#example">example</a> below.</p>
+    </li>
+  </ul>
+
+  <h3 id="manifest-example">Manifest and resource file examples</h3>
+
+  <p>The following example shows a sample manifest and its corresponding resource file:</p>
+  <pre>
+&lt;manifest ...&gt;
+    &lt;uses-feature android:name="android.hardware.usb.host" /&gt;
+    &lt;uses-sdk android:minSdkVersion="12" /&gt;
+    ...
+    &lt;application&gt;
+        &lt;activity ...&gt;
+            ...
+            &lt;intent-filter&gt;
+                &lt;action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /&gt;
+            &lt;/intent-filter&gt;
+
+            &lt;meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
+                android:resource="@xml/device_filter" /&gt;
+        &lt;/activity&gt;
+    &lt;/application&gt;
+&lt;/manifest&gt;
+</pre>
+
+  <p>In this case, the following resource file should be saved in
+  <code>res/xml/device_filter.xml</code> and specifies that any USB device with the corresponding
+  vendor ID and product ID should be filtered. These IDs are specific to the device and are
+  specified by the device's manufacturer:</p>
+  <pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+
+&lt;resources&gt;
+    &lt;usb-device vendor-id="1234" product-id="5678" /&gt;
+&lt;/resources&gt;
+</pre>
+
+  <h2 id="working-d">Working with Devices</h2>
+
+  <p>When users connect USB devices to an Android-powered device, the Android system can determine
+  whether your application is interested in the connected device. If so, you can set up
+  communication with the device if desired. To do this, your application has to:</p>
+
+  <ol>
+    <li>Discover connected USB devices by using an intent filter to be notified when the user
+    connects a USB device or by enumerating USB devices that are already connected.</li>
+
+    <li>Ask the user for permission to connect to the USB device, if not already obtained.</li>
+
+    <li>Communicate with the USB device by reading and writing data on the appropriate interface
+    endpoints.</li>
+  </ol>
+
+  <h3 id="discovering-d">Discovering a device</h3>
+
+  <p>Your application can discover USB devices by either using an intent filter to be notified when
+  the user connects a device or by enumerating USB devices that are already connected. Using an
+  intent filter is useful if you want to be able to have your application automatically detect a
+  desired device. Enumerating connected USB devices is useful if you want to get a list of all
+  connected devices or if your application did not filter for an intent.</p>
+
+  <h4 id="using-intents">Using an intent filter</h4>
+
+  <p>To have your application discover a particular USB device, you can specify an intent filter to
+  filter for the <code>android.hardware.usb.action.USB_DEVICE_ATTACHED</code> intent. Along with
+  this intent filter, you need to specify a resource file that specifies properties of the USB
+  device, such as product and vendor ID. When users connect a device that matches your device
+  filter, the system presents them with a dialog that asks if they want to start your application.
+  If users accept, your application automatically has permission to access the device until the
+  device is disconnected.</p>
+
+  <p>The following example shows how to declare the intent filter:</p>
+  <pre>
+&lt;activity ...&gt;
+...
+    &lt;intent-filter&gt;
+        &lt;action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /&gt;
+    &lt;/intent-filter&gt;
+
+    &lt;meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
+        android:resource="@xml/device_filter" /&gt;
+&lt;/activity&gt;
+</pre>
+
+  <p>The following example shows how to declare the corresponding resource file that specifies the
+  USB devices that you're interested in:</p>
+  <pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+
+&lt;resources&gt;
+    &lt;usb-device vendor-id="1234" product-id="5678" /&gt;
+&lt;/resources&gt;
+</pre><!-- REMEMBER TO ADD PROTOCOL, and device class and subclass, if applicable -->
+
+  <p>In your activity, you can obtain the {@link android.hardware.usb.UsbDevice} that represents
+  the attached device from the intent like this:</p>
+  <pre>
+UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+</pre>
+
+  <h4>Enumerating devices</h4>
+
+  <p>If your application is interested in inspecting all of the USB devices currently connected
+  while your application is running, it can enumerate devices on the bus. Use the {@link
+  android.hardware.usb.UsbManager#getDeviceList() getDeviceList()} method to get a hash map of all
+  the USB devices that are connected. The hash map is keyed by the USB device's name if you want to
+  obtain a device from the map.</p>
+  <pre>
+UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
+...  
+HashMap&lt;String, UsbDevice&gt; deviceList = manager.getDeviceList();
+Iterator&lt;UsbDevice&gt; deviceIterator  = deviceList.values().iterator();
+while(deviceIterator.hasNext()){
+    UsbDevice device = deviceIterator.next();
+    // your code
+}
+</pre>
+
+  <p>If desired, you can also just obtain an iterator from the hash map and process each device one
+  by one:</p>
+  <pre>
+UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
+...
+HashMap&lt;String, UsbDevice&gt; deviceList = manager.getDeviceList();
+Iterator&lt;UsbDevice&gt; deviceIterator = deviceList.values().iterator();
+while(deviceIterator.hasNext()){
+    UsbDevice device = deviceIterator.next()
+    //your code
+}
+</pre>
+
+  <h3 id="permission-d">Obtaining permission to communicate with a device</h3>
+
+  <p>Before communicating with the USB device, your applicaton must have permission from your
+  users.</p>
+
+  <p class="note"><strong>Note:</strong> If your application <a href="#using-intents">uses an
+  intent filter</a> to discover USB devices as they're connected, it automatically receives
+  permission if the user allows your application to handle the intent. If not, you must request
+  permission explicitly in your application before connecting to the device.</p>
+
+  <p>Explicitly asking for permission might be neccessary in some situations such as when your
+  application enumerates USB devices that are already connected and then wants to communicate with
+  one. You must check for permission to access a device before trying to communicate with it. If
+  not, you will receive a runtime error if the user denied permission to access the device.</p>
+
+  <p>To explicitly obtain permission, first create a broadcast receiver. This receiver listens for
+  the intent that gets broadcast when you call {@link
+  android.hardware.usb.UsbManager#requestPermission requestPermission()}. The call to {@link
+  android.hardware.usb.UsbManager#requestPermission requestPermission()} displays a dialog to the
+  user asking for permission to connect to the device. The following sample code shows how to
+  create the broadcast receiver:</p>
+  <pre>
+private static final String ACTION_USB_PERMISSION =
+    "com.android.example.USB_PERMISSION";
+private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
+
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        if (ACTION_USB_PERMISSION.equals(action)) {
+            synchronized (this) {
+                UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+
+                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+                    if(device != null){
+                      //call method to set up device communication
+                   }
+                } 
+                else {
+                    Log.d(TAG, "permission denied for device " + device);
+                }
+            }
+        }
+    }
+};
+</pre>
+
+  <p>To register the broadcast receiver, add this in your <code>onCreate()</code> method in your
+  activity:</p>
+  <pre>
+UsbManager mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
+private static final String ACTION_USB_PERMISSION =
+    "com.android.example.USB_PERMISSION";
+...
+mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
+IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
+registerReceiver(mUsbReceiver, filter);
+</pre>
+
+  <p>To display the dialog that asks users for permission to connect to the device, call the {@link
+  android.hardware.usb.UsbManager#requestPermission requestPermission()} method:</p>
+  <pre>
+UsbDevice device;
+...
+mUsbManager.requestPermission(device, mPermissionIntent);
+</pre>
+
+  <p>When users reply to the dialog, your broadcast receiver receives the intent that contains the
+  {@link android.hardware.usb.UsbManager#EXTRA_PERMISSION_GRANTED} extra, which is a boolean
+  representing the answer. Check this extra for a value of true before connecting to the
+  device.</p>
+
+  <h3 id="communicating-d">Communicating with a device</h3>
+
+  <p>Communication with a USB device can be either synchronous or asynchronous. In either case, you
+  should create a new thread on which to carry out all data transmissions, so you don't block the
+  UI thread. To properly set up communication with a device, you need to obtain the appropriate
+  {@link android.hardware.usb.UsbInterface} and {@link android.hardware.usb.UsbEndpoint} of the
+  device that you want to communicate on and send requests on this endpoint with a {@link
+  android.hardware.usb.UsbDeviceConnection}. In general, your code should:</p>
+
+  <ul>
+    <li>Check a {@link android.hardware.usb.UsbDevice} object's attributes, such as product ID,
+    vendor ID, or device class to figure out whether or not you want to communicate with the
+    device.</li>
+
+    <li>When you are certain that you want to communicate with the device, find the appropriate
+    {@link android.hardware.usb.UsbInterface} that you want to use to communicate along with the
+    appropriate {@link android.hardware.usb.UsbEndpoint} of that interface. Interfaces can have one
+    or more endpoints, and commonly will have an input and output endpoint for two-way
+    communication.</li>
+
+    <li>When you find the correct endpoint, open a {@link android.hardware.usb.UsbDeviceConnection}
+    on that endpoint.</li>
+
+    <li>Supply the data that you want to transmit on the endpoint with the {@link
+    android.hardware.usb.UsbDeviceConnection#bulkTransfer bulkTransfer()} or {@link
+    android.hardware.usb.UsbDeviceConnection#controlTransfer controlTransfer()} method. You should
+    carry out this step in another thread to prevent blocking the main UI thread. For more
+    information about using threads in Android, see <a href=
+    "{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes and
+    Threads</a>.</li>
+  </ul>
+
+  <p>The following code snippet is a trivial way to do a synchronous data transfer. Your code
+  should have more logic to correctly find the correct interface and endpoints to communicate on
+  and also should do any transferring of data in a different thread than the main UI thread:</p>
+  <pre>
+private Byte[] bytes
+private static int TIMEOUT = 0;
+private boolean forceClaim = true;
+
+...
+
+UsbInterface intf = device.getInterface(0);
+UsbEndpoint endpoint = intf.getEndpoint(0);
+UsbDeviceConnection connection = mUsbManager.openDevice(device); 
+connection.claimInterface(intf, forceClaim);
+connection.bulkTransfer(endpoint, bytes, bytes.length, TIMEOUT); //do in another thread
+</pre>
+
+  <p>To send data asynchronously, use the {@link android.hardware.usb.UsbRequest} class to {@link
+  android.hardware.usb.UsbRequest#initialize initialize} and {@link
+  android.hardware.usb.UsbRequest#queue queue} an asynchronous request, then wait for the result
+  with {@link android.hardware.usb.UsbDeviceConnection#requestWait requestWait()}.</p>
+
+  <p>For more information, see the <a href=
+  "{@docRoot}resources/samples/USB/AdbTest/index.html">AdbTest sample</a>, which shows how to do
+  asynchronous bulk transfers, and the <a href=
+  "{@docRoot}resources/samples/USB/MissileLauncher/index.html">MissleLauncher sample</a>, which
+  shows how to listen on an interrupt endpoint asynchronously.</p>
+
+  <h3 id="terminating-d">Terminating communication with a device</h3>
+
+  <p>When you are done communicating with a device or if the device was detached, close the {@link
+  android.hardware.usb.UsbInterface} and {@link android.hardware.usb.UsbDeviceConnection} by
+  calling {@link android.hardware.usb.UsbDeviceConnection#releaseInterface releaseInterface()} and
+  {@link android.hardware.usb.UsbDeviceConnection#close() close()}. To listen for detached events,
+  create a broadcast receiver like below:</p>
+  <pre>
+BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction(); 
+
+      if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
+            UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+            if (device != null) {
+                // call your method that cleans up and closes communication with the device
+            }
+        }
+    }
+};
+</pre>
+
+  <p>Creating the broadcast receiver within the application, and not the manifest, allows your
+  application to only handle detached events while it is running. This way, detached events are
+  only sent to the application that is currently running and not broadcast to all applications.</p>
+
diff --git a/docs/html/guide/topics/usb/index.jd b/docs/html/guide/topics/usb/index.jd
new file mode 100644
index 0000000..18af06a
--- /dev/null
+++ b/docs/html/guide/topics/usb/index.jd
@@ -0,0 +1,67 @@
+page.title=USB Host and Accessory
+@jd:body
+
+  <div id="qv-wrapper">
+    <div id="qv">
+      <h2>Topics</h2>
+
+      <ol>
+        <li><a href="{@docRoot}/guide/topics/USB/accessory.jd">USB Accessory</a></li>
+
+        <li><a href="{@docRoot}/guide/topics/USB/host.jd">USB Host</a></li>
+      </ol>
+    </div>
+  </div>
+
+  <p>Android supports a variety of USB peripherals and Android USB accessories (hardware that
+  implements the Android accessory protocol) through two modes: USB accessory and USB host. In USB
+  accessory mode, the external USB hardware act as the USB hosts. Examples of accessories might
+  include robotics controllers; docking stations; diagnostic and musical equipment; kiosks; card
+  readers; and much more. This gives Android-powered devices that do not have host capabilities the
+  ability to interact with USB hardware. Android USB accessories must be designed to work with
+  Android-powered devices and must adhere to the <a href=
+  "http://accessories.android.com/demokit">Android accessory communication protocol</a>. In USB
+  host mode, the Android-powered device acts as the host. Examples of devices include digital
+  cameras, keyboards, mice, and game controllers. USB devices that are designed for a wide range of
+  applications and environments can still interact with Android applications that can correctly
+  communicate with the device.</p>
+
+  <p>Figure 1 shows the differences between the two modes. When the Android-powered device is in
+  host mode, it acts as the USB host and powers the bus. When the Android-powered device is in USB
+  accessory mode, the connected USB hardware (an Android USB accessory in this case) acts as the
+  host and powers the bus.</p><img src="{@docRoot}images/usb-host-accessory.png" alt="">
+
+  <p class="img-caption"><strong>Figure 1.</strong> USB Host and Accessory Modes</p>
+
+  <p>USB accessory and host modes are directly supported in Android 3.1 (API level 12) or newer
+  platforms. USB accessory mode is also backported to Android 2.3.4 (API level 10) as an add-on
+  library to support a broader range of devices. Device manufacturers can choose whether or not to
+  include the add-on library on the device's system image.</p>
+
+  <p class="note"><strong>Note:</strong> Support for USB host and accessory modes are ultimately
+  dependant on the device's hardware, regardless of platform level. You can filter for devices that
+  support USB host and accessory through a <a href=
+  "{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature&gt;</a> element. See
+  the USB <a href="{@docRoot}guide/topics/USB/accessory.html">accessory</a> and <a href=
+  "{@docRoot}guide/topics/USB/host.html">host</a> documentation for more details.</p>
+
+  <h2>Debugging considerations</h2>
+
+  <p>When debugging applications that use USB accessory or host features, you most likely will have
+  USB hardware connected to your Android-powered device. This will prevent you from having an
+  <code>adb</code> connection to the Android-powered device via USB. You can still access
+  <code>adb</code> over a network connection. To enable <code>adb</code> over a network
+  connection:</p>
+
+  <ol>
+    <li>Connect the Android-powered device via USB to your computer.</li>
+
+    <li>From your SDK <code>platform-tools/</code> directory, enter <code>adb tcpip 5555</code> at
+    the command prompt.</li>
+
+    <li>Enter <code>adb connect &lt;device-ip-address&gt;:5555</code> You should now be connected
+    to the Android-powered device and can issue the usual <code>adb</code> commands like <code>adb
+    logcat</code>.</li>
+
+    <li>To set your device to listen on USB, enter <code>adb usb</code>.</li>
+  </ol>
diff --git a/docs/html/images/admin/device-admin-activate-prompt.png b/docs/html/images/admin/device-admin-activate-prompt.png
old mode 100755
new mode 100644
index fd001bd..2851194
--- a/docs/html/images/admin/device-admin-activate-prompt.png
+++ b/docs/html/images/admin/device-admin-activate-prompt.png
Binary files differ
diff --git a/docs/html/images/admin/device-admin-app.png b/docs/html/images/admin/device-admin-app.png
old mode 100755
new mode 100644
index d966a28..c96defc
--- a/docs/html/images/admin/device-admin-app.png
+++ b/docs/html/images/admin/device-admin-app.png
Binary files differ
diff --git a/docs/html/images/usb-host-accessory.png b/docs/html/images/usb-host-accessory.png
new file mode 100644
index 0000000..f82fd6f
--- /dev/null
+++ b/docs/html/images/usb-host-accessory.png
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index 78f71ac..d5f19a1 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -129,17 +129,20 @@
     'sdk': {
       'layout':"imgLeft",
       'icon':"sdk-small.png",
-      'name':"Android 3.0",
+      'name':"Android 3.1",
       'img':"honeycomb-android.png",
-      'title':"Android 3.0 is here!",
-      'desc': "<p>Android 3.0 is now available for the Android SDK. It offers a redesigned UI and "
-+ "all new developer APIs for an optimized experience on tablets and similar devices. "
-+ "For more information about what's in Android 3.0, read the "
-+ "<a href='{@docRoot}sdk/android-3.0.html'>version notes</a>.</p>"
+      'title':"Android 3.1 now available!",
+      'desc': "<p>Android 3.1 includes new developer features such as APIs for USB "
++ "accessories, MTP/PTP, and RTP, as well as new input events from mice, trackballs, joysticks, "
++ "and more.</p>"
++ "<p>For more information about all the new APIs in Android 3.1, read the "
++ "<a href='{@docRoot}sdk/android-3.1.html'>version notes</a>.</p>"
+/*
 + "<p>If you have an existing SDK, add Android 3.0 as an "
 + "<a href='{@docRoot}sdk/adding-components.html'>SDK "
 + "component</a>. If you're new to Android, install the "
 + "<a href='{@docRoot}sdk/index.html'>SDK starter package</a>."
+*/
     },
 
     'tv': {
@@ -152,8 +155,7 @@
                + "for television built on Android. Google "
                + "has partnered with Sony and Logitech to integrate "
                + "this platform into TVs, blu-ray players, and companion "
-               + "boxes. An add-on for the Android SDK will be "
-               + "available early next year. </p>"
+               + "boxes. </p>"
                + "<p><a href='http://www.google.com/tv/'>Learn more about "
                + "Google TV &raquo;</a></p>"
     },
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index 5d7b651..368164d 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -52,7 +52,7 @@
 <div class="dashboard-panel">
 
 <img alt="" height="250" width="460"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:2.7,3.5,27.2,63.9,0.8,1.7,0.2&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0&chco=c4df9b,6fad0c" />
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:2.3,3.0,24.5,65.9,1.0,3.0,0.3&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0&chco=c4df9b,6fad0c" />
 
 <table>
 <tr>
@@ -60,16 +60,16 @@
   <th>API Level</th>
   <th>Distribution</th>
 </tr>
-<tr><td>Android 1.5</td><td>3</td><td>2.7%</td></tr> 
-<tr><td>Android 1.6</td><td>4</td><td>3.5%</td></tr> 
-<tr><td>Android 2.1</td><td>7</td><td>27.2%</td></tr> 
-<tr><td>Android 2.2</td><td>8</td><td>63.9%</td></tr> 
-<tr><td>Android 2.3</td><td>9</td><td>0.8%</td></tr> 
-<tr><td>Android 2.3.3</td><td>10</td><td>1.7%</td></tr> 
-<tr><td>Android 3.0</td><td>11</td><td>0.2%</td></tr> 
+<tr><td>Android 1.5</td><td>3</td><td>2.3%</td></tr> 
+<tr><td>Android 1.6</td><td>4</td><td>3.0%</td></tr> 
+<tr><td>Android 2.1</td><td>7</td><td>24.5%</td></tr> 
+<tr><td>Android 2.2</td><td>8</td><td>65.9%</td></tr> 
+<tr><td>Android 2.3</td><td>9</td><td>1.0%</td></tr> 
+<tr><td>Android 2.3.3</td><td>10</td><td>3.0%</td></tr> 
+<tr><td>Android 3.0</td><td>11</td><td>0.3%</td></tr> 
 </table>
 
-<p><em>Data collected during two weeks ending on April 1, 2011</em></p>
+<p><em>Data collected during two weeks ending on May 2, 2011</em></p>
 <!--
 <p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p>
 -->
@@ -98,9 +98,9 @@
 <div class="dashboard-panel">
 
 <img alt="" height="250" width="660" style="padding:5px;background:#fff"
-src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C10/01%7C10/15%7C11/01%7C11/15%7C12/01%7C12/15%7C01/01%7C01/15%7C02/01%7C02/15%7C03/01%7C03/15%7C04/01%7C1%3A%7C2010%7C%7C%7C%7C%7C%7C2011%7C%7C%7C%7C%7C%7C2011%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:99.9,99.9,100.0,99.9,99.8,99.7,100.0,99.9,99.9,99.9,100.0,99.8,99.7|90.2,91.1,92.0,92.7,93.4,94.1,95.2,95.6,96.0,96.3,96.7,96.8,97.0|73.8,75.3,77.4,79.6,82.2,84.4,87.2,88.3,89.7,90.5,91.5,92.0,93.5|33.4,34.5,37.1,40.5,44.3,47.7,51.8,54.3,58.3,59.7,61.5,63.0,66.3|0.0,0.0,0.0,0.0,0.0,0.0,0.4,0.6,0.7,0.8,1.1,1.7,2.5|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.7&chm=b,c3df9b,0,1,0|tAndroid 1.6,689326,1,0,15,,t::-5|b,b4db77,1,2,0|tAndroid 2.1,547a19,2,0,15,,t::-5|b,a5db51,2,3,0|tAndroid 2.2,3f5e0e,3,0,15,,t::-5|b,96dd28,3,4,0|b,83c916,4,5,0|B,6fad0c,5,6,0&chg=7,25&chdl=Android 1.5|Android 1.6|Android 2.1|Android 2.2|Android 2.3|Android 2.3.3&chco=add274,9dd14f,8ece2a,7ab61c,659b11,507d08" />
+src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C11/01%7C11/15%7C12/01%7C12/15%7C01/01%7C01/15%7C02/01%7C02/15%7C03/01%7C03/15%7C04/01%7C04/15%7C05/01%7C1%3A%7C2010%7C%7C%7C%7C2011%7C%7C%7C%7C%7C%7C%7C%7C2011%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:100.0,99.9,99.8,99.7,100.0,99.9,99.9,99.9,100.0,99.8,99.7,99.6,99.6|92.0,92.7,93.4,94.1,95.2,95.6,96.0,96.3,96.7,96.8,97.0,97.1,97.3|77.4,79.6,82.2,84.4,87.2,88.3,89.7,90.5,91.5,92.0,93.5,93.9,94.3|37.1,40.5,44.3,47.7,51.8,54.3,58.3,59.7,61.5,63.0,66.4,68.0,69.8|0.0,0.0,0.0,0.0,0.4,0.6,0.7,0.8,1.1,1.7,2.5,3.1,4.0|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.7,2.2,3.0&chm=b,c3df9b,0,1,0|tAndroid 1.6,689326,1,0,15,,t::-5|b,b4db77,1,2,0|tAndroid 2.1,547a19,2,0,15,,t::-5|b,a5db51,2,3,0|tAndroid 2.2,3f5e0e,3,0,15,,t::-5|b,96dd28,3,4,0|b,83c916,4,5,0|B,6fad0c,5,6,0&chg=7,25&chdl=Android 1.5|Android 1.6|Android 2.1|Android 2.2|Android 2.3|Android 2.3.3&chco=add274,9dd14f,8ece2a,7ab61c,659b11,507d08" />
 
-<p><em>Last historical dataset collected during two weeks ending on April 1, 2011</em></p>
+<p><em>Last historical dataset collected during two weeks ending on May 2, 2011</em></p>
 
 
 </div><!-- end dashboard-panel -->
diff --git a/docs/html/resources/resources-data.js b/docs/html/resources/resources-data.js
index 14118bb..03a5c02 100644
--- a/docs/html/resources/resources-data.js
+++ b/docs/html/resources/resources-data.js
@@ -606,6 +606,16 @@
     }
   },
   {
+    tags: ['sample', 'new', 'newfeature'],
+    path: 'samples/USB/index.html',
+    title: {
+      en: 'USB'
+    },
+    description: {
+      en: 'A set of samples that demonstrate how to use various features of the USB APIs.'
+    }
+  },
+  {
     tags: ['sample', 'ui', 'widgets'],
     path: 'samples/Wiktionary/index.html',
     title: {
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index 6b9a5ce..3240b57 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -113,7 +113,8 @@
       </li>
     </ul>
     <ul>
-      <li><a href="<?cs var:toroot ?>sdk/tools-notes.html">SDK Tools, r10</a> <span class="new">new!</span></li>
+      <li><a href="<?cs var:toroot ?>sdk/tools-notes.html">SDK Tools, r11</a> <span
+class="new">new!</span></li>
       <li><a href="<?cs var:toroot ?>sdk/win-usb.html">Google USB Driver, r4</a></li>
     </ul>
   </li>
@@ -137,7 +138,7 @@
       <span style="display:none" class="ja"></span>
       <span style="display:none" class="zh-CN"></span>
       <span style="display:none" class="zh-TW"></span></a>
-      <span class="new">new!</span></li>
+     <!-- <span class="new">new!</span> --></li>
     </ul>
   </li>
   <li>
diff --git a/docs/html/sdk/tools-notes.jd b/docs/html/sdk/tools-notes.jd
index 28d8bdd..354fec9 100644
--- a/docs/html/sdk/tools-notes.jd
+++ b/docs/html/sdk/tools-notes.jd
@@ -70,6 +70,33 @@
   <dl>
 <dt>Dependencies:</dt>
 <dd>
+<p>If you are developing in Eclipse with ADT, note that the SDK Tools r11 is designed for use with
+ADT 10.0.1 and later. If you haven't already, we highly recommend updating your <a
+href="{@docRoot}sdk/eclipse-adt.html">ADT Plugin</a> to 10.0.1.</p>
+
+<p>If you are developing outside Eclipse, you must have <a href="http://ant.apache.org/">Apache
+Ant</a> 1.8 or later.</p>
+
+<dt>General notes:</dt>
+<dd>
+  <ul>
+    <li>Miscellaneous emulator changes to support Android 3.1.</li>
+  </ul>
+</dd>
+</dl>
+</div>
+</div>
+
+
+<div class="toggleable closed">
+  <a href="#" onclick="return toggleDiv(this)">
+        <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px"
+width="9px" />
+SDK Tools, Revision 10</a> <em>(February 2011)</em>
+  <div class="toggleme">
+  <dl>
+<dt>Dependencies:</dt>
+<dd>
 <p>If you are developing in Eclipse with ADT, note that the SDK Tools r10 is
 designed for use with ADT 10.0.0 and later. After installing SDK Tools r10, we
 highly recommend updating your ADT Plugin to 10.0.0.</p>
@@ -80,7 +107,8 @@
 <dt>General notes:</dt>
 <dd>
   <ul>
-    <li>The tools now automatically generate Java Programming Language source files (in the <code>gen</code> directory) and
+    <li>The tools now automatically generate Java Programming Language source files (in the
+<code>gen</code> directory) and
     bytecode (in the <code>res/raw</code> directory) from your native <code>.rs</code> files</li>
   </ul>
 </dd>
@@ -400,7 +428,7 @@
 <dt>DDMS:</dt>
 <dd>
 <ul>
-<li>Adds a button to dump HPROF file for running appplications (app must be able
+<li>Adds a button to dump HPROF file for running applications (app must be able
 to write to the sdcard).</li>
 <li>Button to start/stop profiling of a running application (app must be able to
 write to the sdcard). Upon stop, Traceview will automatically be launched to
diff --git a/graphics/java/android/graphics/Movie.java b/graphics/java/android/graphics/Movie.java
index 95e9946..4a33453 100644
--- a/graphics/java/android/graphics/Movie.java
+++ b/graphics/java/android/graphics/Movie.java
@@ -46,6 +46,8 @@
     public static native Movie decodeByteArray(byte[] data, int offset,
                                                int length);
 
+    private static native void nativeDestructor(int nativeMovie);
+
     public static Movie decodeFile(String pathName) {
         InputStream is;
         try {
@@ -57,6 +59,15 @@
         return decodeTempStream(is);
     }
 
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            nativeDestructor(mNativeMovie);
+        } finally {
+            super.finalize();
+        }
+    }
+
     private static Movie decodeTempStream(InputStream is) {
         Movie moov = null;
         try {
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index cfae0c1..3c43a39 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -34,8 +34,9 @@
  * the stream to be skipped.
  *
  * <p>When sampling from the texture one should first transform the texture coordinates using the
- * matrix queried via {@link #getTransformMatrix}.  The transform matrix may change each time {@link
- * #updateTexImage} is called, so it should be re-queried each time the texture image is updated.
+ * matrix queried via {@link #getTransformMatrix(float[])}.  The transform matrix may change each
+ * time {@link #updateTexImage} is called, so it should be re-queried each time the texture image
+ * is updated.
  * This matrix transforms traditional 2D OpenGL ES texture coordinate column vectors of the form (s,
  * t, 0, 1) where s and t are on the inclusive interval [0, 1] to the proper sampling location in
  * the streamed texture.  This transform compensates for any properties of the image stream source
@@ -63,8 +64,13 @@
     private EventHandler mEventHandler;
     private OnFrameAvailableListener mOnFrameAvailableListener;
 
-    @SuppressWarnings("unused")
-    private int mSurfaceTexture;
+    /**
+     * This field is used by native code, do not access or modify.
+     * 
+     * @hide
+     */
+    @SuppressWarnings({"UnusedDeclaration"})
+    public int mSurfaceTexture;
 
     /**
      * Callback interface for being notified that a new stream frame is available.
@@ -176,10 +182,13 @@
             if (mOnFrameAvailableListener != null) {
                 mOnFrameAvailableListener.onFrameAvailable(SurfaceTexture.this);
             }
-            return;
         }
     }
 
+    /**
+     * This method is invoked from native code only.
+     */
+    @SuppressWarnings({"UnusedDeclaration"})
     private static void postEventFromNative(Object selfRef) {
         WeakReference weakSelf = (WeakReference)selfRef;
         SurfaceTexture st = (SurfaceTexture)weakSelf.get();
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 4c505ec..feb74b8 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -473,25 +473,12 @@
         return rsnScriptCCreate(mContext, resName, cacheDir, script, length);
     }
 
-    native void rsnSamplerBegin(int con);
-    synchronized void nSamplerBegin() {
+    native int  rsnSamplerCreate(int con, int magFilter, int minFilter,
+                                 int wrapS, int wrapT, int wrapR, float aniso);
+    synchronized int nSamplerCreate(int magFilter, int minFilter,
+                                 int wrapS, int wrapT, int wrapR, float aniso) {
         validate();
-        rsnSamplerBegin(mContext);
-    }
-    native void rsnSamplerSet(int con, int param, int value);
-    synchronized void nSamplerSet(int param, int value) {
-        validate();
-        rsnSamplerSet(mContext, param, value);
-    }
-    native void rsnSamplerSet2(int con, int param, float value);
-    synchronized void nSamplerSet2(int param, float value) {
-        validate();
-        rsnSamplerSet2(mContext, param, value);
-    }
-    native int  rsnSamplerCreate(int con);
-    synchronized int nSamplerCreate() {
-        validate();
-        return rsnSamplerCreate(mContext);
+        return rsnSamplerCreate(mContext, magFilter, minFilter, wrapS, wrapT, wrapR, aniso);
     }
 
     native int  rsnProgramStoreCreate(int con, boolean r, boolean g, boolean b, boolean a,
@@ -839,6 +826,9 @@
 
         rs.mDev = rs.nDeviceCreate();
         rs.mContext = rs.nContextCreate(rs.mDev, 0);
+        if (rs.mContext == 0) {
+            throw new RSDriverException("Failed to create RS context.");
+        }
         rs.mMessageThread = new MessageThread(rs);
         rs.mMessageThread.start();
         return rs;
diff --git a/graphics/java/android/renderscript/Sampler.java b/graphics/java/android/renderscript/Sampler.java
index 8e1cac5..98943a1 100644
--- a/graphics/java/android/renderscript/Sampler.java
+++ b/graphics/java/android/renderscript/Sampler.java
@@ -239,21 +239,10 @@
             }
         }
 
-        static synchronized Sampler internalCreate(RenderScript rs, Builder b) {
-            rs.nSamplerBegin();
-            rs.nSamplerSet(0, b.mMin.mID);
-            rs.nSamplerSet(1, b.mMag.mID);
-            rs.nSamplerSet(2, b.mWrapS.mID);
-            rs.nSamplerSet(3, b.mWrapT.mID);
-            rs.nSamplerSet(4, b.mWrapR.mID);
-            rs.nSamplerSet2(5, b.mAniso);
-            int id = rs.nSamplerCreate();
-            return new Sampler(id, rs);
-        }
-
         public Sampler create() {
             mRS.validate();
-            return internalCreate(mRS, this);
+            int id = mRS.nSamplerCreate(mMag.mID, mMin.mID, mWrapS.mID, mWrapT.mID, mWrapR.mID, mAniso);
+            return new Sampler(id, mRS);
         }
     }
 
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 256435f..445f4b5 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -1059,32 +1059,18 @@
 
 // ---------------------------------------------------------------------------
 
-static void
-nSamplerBegin(JNIEnv *_env, jobject _this, RsContext con)
-{
-    LOG_API("nSamplerBegin, con(%p)", con);
-    rsSamplerBegin(con);
-}
-
-static void
-nSamplerSet(JNIEnv *_env, jobject _this, RsContext con, jint p, jint v)
-{
-    LOG_API("nSamplerSet, con(%p), param(%i), value(%i)", con, p, v);
-    rsSamplerSet(con, (RsSamplerParam)p, (RsSamplerValue)v);
-}
-
-static void
-nSamplerSet2(JNIEnv *_env, jobject _this, RsContext con, jint p, jfloat v)
-{
-    LOG_API("nSamplerSet2, con(%p), param(%i), value(%f)", con, p, v);
-    rsSamplerSet2(con, (RsSamplerParam)p, v);
-}
-
 static jint
-nSamplerCreate(JNIEnv *_env, jobject _this, RsContext con)
+nSamplerCreate(JNIEnv *_env, jobject _this, RsContext con, jint magFilter, jint minFilter,
+               jint wrapS, jint wrapT, jint wrapR, jfloat aniso)
 {
     LOG_API("nSamplerCreate, con(%p)", con);
-    return (jint)rsSamplerCreate(con);
+    return (jint)rsSamplerCreate(con,
+                                 (RsSamplerValue)magFilter,
+                                 (RsSamplerValue)minFilter,
+                                 (RsSamplerValue)wrapS,
+                                 (RsSamplerValue)wrapT,
+                                 (RsSamplerValue)wrapR,
+                                 aniso);
 }
 
 // ---------------------------------------------------------------------------
@@ -1280,10 +1266,7 @@
 {"rsnContextBindProgramVertex",      "(II)V",                                 (void*)nContextBindProgramVertex },
 {"rsnContextBindProgramRaster",      "(II)V",                                 (void*)nContextBindProgramRaster },
 
-{"rsnSamplerBegin",                  "(I)V",                                  (void*)nSamplerBegin },
-{"rsnSamplerSet",                    "(III)V",                                (void*)nSamplerSet },
-{"rsnSamplerSet2",                   "(IIF)V",                                (void*)nSamplerSet2 },
-{"rsnSamplerCreate",                 "(I)I",                                  (void*)nSamplerCreate },
+{"rsnSamplerCreate",                 "(IIIIIIF)I",                            (void*)nSamplerCreate },
 
 {"rsnMeshCreate",                    "(III)I",                                (void*)nMeshCreate },
 {"rsnMeshBindVertex",                "(IIII)V",                               (void*)nMeshBindVertex },
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index 3c6dccc..7106bfa 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -20,122 +20,28 @@
 #include <utils/Timers.h>
 #include <camera/ICameraClient.h>
 #include <gui/ISurfaceTexture.h>
+#include <system/camera.h>
 
 namespace android {
 
-/*
- * A set of bit masks for specifying how the received preview frames are
- * handled before the previewCallback() call.
- *
- * The least significant 3 bits of an "int" value are used for this purpose:
- *
- * ..... 0 0 0
- *       ^ ^ ^
- *       | | |---------> determine whether the callback is enabled or not
- *       | |-----------> determine whether the callback is one-shot or not
- *       |-------------> determine whether the frame is copied out or not
- *
- * WARNING:
- * When a frame is sent directly without copying, it is the frame receiver's
- * responsiblity to make sure that the frame data won't get corrupted by
- * subsequent preview frames filled by the camera. This flag is recommended
- * only when copying out data brings significant performance price and the
- * handling/processing of the received frame data is always faster than
- * the preview frame rate so that data corruption won't occur.
- *
- * For instance,
- * 1. 0x00 disables the callback. In this case, copy out and one shot bits
- *    are ignored.
- * 2. 0x01 enables a callback without copying out the received frames. A
- *    typical use case is the Camcorder application to avoid making costly
- *    frame copies.
- * 3. 0x05 is enabling a callback with frame copied out repeatedly. A typical
- *    use case is the Camera application.
- * 4. 0x07 is enabling a callback with frame copied out only once. A typical use
- *    case is the Barcode scanner application.
- */
-#define FRAME_CALLBACK_FLAG_ENABLE_MASK              0x01
-#define FRAME_CALLBACK_FLAG_ONE_SHOT_MASK            0x02
-#define FRAME_CALLBACK_FLAG_COPY_OUT_MASK            0x04
-
-// Typical use cases
-#define FRAME_CALLBACK_FLAG_NOOP                     0x00
-#define FRAME_CALLBACK_FLAG_CAMCORDER                0x01
-#define FRAME_CALLBACK_FLAG_CAMERA                   0x05
-#define FRAME_CALLBACK_FLAG_BARCODE_SCANNER          0x07
-
-// msgType in notifyCallback and dataCallback functions
-enum {
-    CAMERA_MSG_ERROR            = 0x0001,
-    CAMERA_MSG_SHUTTER          = 0x0002,
-    CAMERA_MSG_FOCUS            = 0x0004,
-    CAMERA_MSG_ZOOM             = 0x0008,
-    CAMERA_MSG_PREVIEW_FRAME    = 0x0010,
-    CAMERA_MSG_VIDEO_FRAME      = 0x0020,
-    CAMERA_MSG_POSTVIEW_FRAME   = 0x0040,
-    CAMERA_MSG_RAW_IMAGE        = 0x0080,
-    CAMERA_MSG_COMPRESSED_IMAGE = 0x0100,
-    CAMERA_MSG_RAW_IMAGE_NOTIFY = 0x0200,
-    CAMERA_MSG_ALL_MSGS         = 0xFFFF
-};
-
-// cmdType in sendCommand functions
-enum {
-    CAMERA_CMD_START_SMOOTH_ZOOM     = 1,
-    CAMERA_CMD_STOP_SMOOTH_ZOOM      = 2,
-    // Set the clockwise rotation of preview display (setPreviewDisplay) in
-    // degrees. This affects the preview frames and the picture displayed after
-    // snapshot. This method is useful for portrait mode applications. Note that
-    // preview display of front-facing cameras is flipped horizontally before
-    // the rotation, that is, the image is reflected along the central vertical
-    // axis of the camera sensor. So the users can see themselves as looking
-    // into a mirror.
-    //
-    // This does not affect the order of byte array of CAMERA_MSG_PREVIEW_FRAME,
-    // CAMERA_MSG_VIDEO_FRAME, CAMERA_MSG_POSTVIEW_FRAME, CAMERA_MSG_RAW_IMAGE,
-    // or CAMERA_MSG_COMPRESSED_IMAGE. This is not allowed to be set during
-    // preview.
-    CAMERA_CMD_SET_DISPLAY_ORIENTATION = 3,
-
-    // cmdType to disable/enable shutter sound.
-    // In sendCommand passing arg1 = 0 will disable,
-    // while passing arg1 = 1 will enable the shutter sound.
-    CAMERA_CMD_ENABLE_SHUTTER_SOUND = 4,
-
-    // cmdType to play recording sound.
-    CAMERA_CMD_PLAY_RECORDING_SOUND = 5,
-};
-
-// camera fatal errors
-enum {
-    CAMERA_ERROR_UNKNOWN  = 1,
-    CAMERA_ERROR_SERVER_DIED = 100
-};
-
-enum {
-    CAMERA_FACING_BACK = 0, /* The facing of the camera is opposite to that of the screen. */
-    CAMERA_FACING_FRONT = 1 /* The facing of the camera is the same as that of the screen. */
-};
-
 struct CameraInfo {
-
     /**
-     * The direction that the camera faces to. It should be
-     * CAMERA_FACING_BACK or CAMERA_FACING_FRONT.
+     * The direction that the camera faces to. It should be CAMERA_FACING_BACK
+     * or CAMERA_FACING_FRONT.
      */
     int facing;
 
     /**
      * The orientation of the camera image. The value is the angle that the
-     * camera image needs to be rotated clockwise so it shows correctly on
-     * the display in its natural orientation. It should be 0, 90, 180, or 270.
+     * camera image needs to be rotated clockwise so it shows correctly on the
+     * display in its natural orientation. It should be 0, 90, 180, or 270.
      *
      * For example, suppose a device has a naturally tall screen. The
      * back-facing camera sensor is mounted in landscape. You are looking at
      * the screen. If the top side of the camera sensor is aligned with the
      * right edge of the screen in natural orientation, the value should be
-     * 90. If the top side of a front-facing camera sensor is aligned with
-     * the right of the screen, the value should be 270.
+     * 90. If the top side of a front-facing camera sensor is aligned with the
+     * right of the screen, the value should be 270.
      */
     int orientation;
 };
diff --git a/include/camera/CameraHardwareInterface.h b/include/camera/CameraHardwareInterface.h
deleted file mode 100644
index 3f34120..0000000
--- a/include/camera/CameraHardwareInterface.h
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
-#define ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
-
-#include <binder/IMemory.h>
-#include <ui/egl/android_natives.h>
-#include <utils/RefBase.h>
-#include <surfaceflinger/ISurface.h>
-#include <ui/android_native_buffer.h>
-#include <ui/GraphicBuffer.h>
-#include <camera/Camera.h>
-#include <camera/CameraParameters.h>
-
-namespace android {
-
-typedef void (*notify_callback)(int32_t msgType,
-                                int32_t ext1,
-                                int32_t ext2,
-                                void* user);
-
-typedef void (*data_callback)(int32_t msgType,
-                              const sp<IMemory>& dataPtr,
-                              void* user);
-
-typedef void (*data_callback_timestamp)(nsecs_t timestamp,
-                                        int32_t msgType,
-                                        const sp<IMemory>& dataPtr,
-                                        void* user);
-
-/**
- * CameraHardwareInterface.h defines the interface to the
- * camera hardware abstraction layer, used for setting and getting
- * parameters, live previewing, and taking pictures.
- *
- * It is a referenced counted interface with RefBase as its base class.
- * CameraService calls openCameraHardware() to retrieve a strong pointer to the
- * instance of this interface and may be called multiple times. The
- * following steps describe a typical sequence:
- *
- *   -# After CameraService calls openCameraHardware(), getParameters() and
- *      setParameters() are used to initialize the camera instance.
- *      CameraService calls getPreviewHeap() to establish access to the
- *      preview heap so it can be registered with SurfaceFlinger for
- *      efficient display updating while in preview mode.
- *   -# startPreview() is called.  The camera instance then periodically
- *      sends the message CAMERA_MSG_PREVIEW_FRAME (if enabled) each time
- *      a new preview frame is available.  If data callback code needs to use
- *      this memory after returning, it must copy the data.
- *
- * Prior to taking a picture, CameraService calls autofocus(). When auto
- * focusing has completed, the camera instance sends a CAMERA_MSG_FOCUS notification,
- * which informs the application whether focusing was successful. The camera instance
- * only sends this message once and it is up  to the application to call autoFocus()
- * again if refocusing is desired.
- *
- * CameraService calls takePicture() to request the camera instance take a
- * picture. At this point, if a shutter, postview, raw, and/or compressed callback
- * is desired, the corresponding message must be enabled. As with CAMERA_MSG_PREVIEW_FRAME,
- * any memory provided in a data callback must be copied if it's needed after returning.
- */
-class CameraHardwareInterface : public virtual RefBase {
-public:
-    virtual ~CameraHardwareInterface() { }
-
-    /** Set the ANativeWindow to which preview frames are sent */
-    virtual status_t setPreviewWindow(const sp<ANativeWindow>& buf) = 0;
-
-    /** Set the notification and data callbacks */
-    virtual void setCallbacks(notify_callback notify_cb,
-                              data_callback data_cb,
-                              data_callback_timestamp data_cb_timestamp,
-                              void* user) = 0;
-
-    /**
-     * The following three functions all take a msgtype,
-     * which is a bitmask of the messages defined in
-     * include/ui/Camera.h
-     */
-
-    /**
-     * Enable a message, or set of messages.
-     */
-    virtual void        enableMsgType(int32_t msgType) = 0;
-
-    /**
-     * Disable a message, or a set of messages.
-     *
-     * Once received a call to disableMsgType(CAMERA_MSG_VIDEO_FRAME), camera hal
-     * should not rely on its client to call releaseRecordingFrame() to release
-     * video recording frames sent out by the cameral hal before and after the
-     * disableMsgType(CAMERA_MSG_VIDEO_FRAME) call. Camera hal clients must not
-     * modify/access any video recording frame after calling
-     * disableMsgType(CAMERA_MSG_VIDEO_FRAME).
-     */
-    virtual void        disableMsgType(int32_t msgType) = 0;
-
-    /**
-     * Query whether a message, or a set of messages, is enabled.
-     * Note that this is operates as an AND, if any of the messages
-     * queried are off, this will return false.
-     */
-    virtual bool        msgTypeEnabled(int32_t msgType) = 0;
-
-    /**
-     * Start preview mode.
-     */
-    virtual status_t    startPreview() = 0;
-
-    /**
-     * Stop a previously started preview.
-     */
-    virtual void        stopPreview() = 0;
-
-    /**
-     * Returns true if preview is enabled.
-     */
-    virtual bool        previewEnabled() = 0;
-
-    /**
-     * Request the camera hal to store meta data or real YUV data in
-     * the video buffers send out via CAMERA_MSG_VIDEO_FRRAME for a
-     * recording session. If it is not called, the default camera
-     * hal behavior is to store real YUV data in the video buffers.
-     *
-     * This method should be called before startRecording() in order
-     * to be effective.
-     *
-     * If meta data is stored in the video buffers, it is up to the
-     * receiver of the video buffers to interpret the contents and
-     * to find the actual frame data with the help of the meta data
-     * in the buffer. How this is done is outside of the scope of
-     * this method.
-     *
-     * Some camera hal may not support storing meta data in the video
-     * buffers, but all camera hal should support storing real YUV data
-     * in the video buffers. If the camera hal does not support storing
-     * the meta data in the video buffers when it is requested to do
-     * do, INVALID_OPERATION must be returned. It is very useful for
-     * the camera hal to pass meta data rather than the actual frame
-     * data directly to the video encoder, since the amount of the
-     * uncompressed frame data can be very large if video size is large.
-     *
-     * @param enable if true to instruct the camera hal to store
-     *      meta data in the video buffers; false to instruct
-     *      the camera hal to store real YUV data in the video
-     *      buffers.
-     *
-     * @return OK on success.
-     */
-    virtual status_t    storeMetaDataInBuffers(bool enable) {
-                            return enable? INVALID_OPERATION: OK;
-                        }
-
-    /**
-     * Start record mode. When a record image is available a CAMERA_MSG_VIDEO_FRAME
-     * message is sent with the corresponding frame. Every record frame must be released
-     * by a cameral hal client via releaseRecordingFrame() before the client calls
-     * disableMsgType(CAMERA_MSG_VIDEO_FRAME). After the client calls
-     * disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is camera hal's responsibility
-     * to manage the life-cycle of the video recording frames, and the client must
-     * not modify/access any video recording frames.
-     */
-    virtual status_t    startRecording() = 0;
-
-    /**
-     * Stop a previously started recording.
-     */
-    virtual void        stopRecording() = 0;
-
-    /**
-     * Returns true if recording is enabled.
-     */
-    virtual bool        recordingEnabled() = 0;
-
-    /**
-     * Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME.
-     *
-     * It is camera hal client's responsibility to release video recording
-     * frames sent out by the camera hal before the camera hal receives
-     * a call to disableMsgType(CAMERA_MSG_VIDEO_FRAME). After it receives
-     * the call to disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is camera hal's
-     * responsibility of managing the life-cycle of the video recording
-     * frames.
-     */
-    virtual void        releaseRecordingFrame(const sp<IMemory>& mem) = 0;
-
-    /**
-     * Start auto focus, the notification callback routine is called
-     * with CAMERA_MSG_FOCUS once when focusing is complete. autoFocus()
-     * will be called again if another auto focus is needed.
-     */
-    virtual status_t    autoFocus() = 0;
-
-    /**
-     * Cancels auto-focus function. If the auto-focus is still in progress,
-     * this function will cancel it. Whether the auto-focus is in progress
-     * or not, this function will return the focus position to the default.
-     * If the camera does not support auto-focus, this is a no-op.
-     */
-    virtual status_t    cancelAutoFocus() = 0;
-
-    /**
-     * Take a picture.
-     */
-    virtual status_t    takePicture() = 0;
-
-    /**
-     * Cancel a picture that was started with takePicture.  Calling this
-     * method when no picture is being taken is a no-op.
-     */
-    virtual status_t    cancelPicture() = 0;
-
-    /**
-     * Set the camera parameters. This returns BAD_VALUE if any parameter is
-     * invalid or not supported. */
-    virtual status_t    setParameters(const CameraParameters& params) = 0;
-
-    /** Return the camera parameters. */
-    virtual CameraParameters  getParameters() const = 0;
-
-    /**
-     * Send command to camera driver.
-     */
-    virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) = 0;
-
-    /**
-     * Release the hardware resources owned by this object.  Note that this is
-     * *not* done in the destructor.
-     */
-    virtual void release() = 0;
-
-    /**
-     * Dump state of the camera hardware
-     */
-    virtual status_t dump(int fd, const Vector<String16>& args) const = 0;
-};
-
-/**
- * The functions need to be provided by the camera HAL.
- *
- * If getNumberOfCameras() returns N, the valid cameraId for getCameraInfo()
- * and openCameraHardware() is 0 to N-1.
- */
-extern "C" int HAL_getNumberOfCameras();
-extern "C" void HAL_getCameraInfo(int cameraId, struct CameraInfo* cameraInfo);
-/* HAL should return NULL if it fails to open camera hardware. */
-extern "C" sp<CameraHardwareInterface> HAL_openCameraHardware(int cameraId);
-
-};  // namespace android
-
-#endif
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index db81721..513239f 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -309,6 +309,25 @@
     // 0.3333, EV is -2.
     // Example value: "0.333333333" or "0.5". Read only.
     static const char KEY_EXPOSURE_COMPENSATION_STEP[];
+    // The state of the auto-exposure lock. "true" means that auto-exposure is
+    // locked to its current value and will not change. "false" means the
+    // auto-exposure routine is free to change exposure settings. Changing
+    // exposure compensation settings will still affect the exposure settings
+    // while auto-exposure is locked. Stopping preview or taking a still image
+    // will release the lock. However, the lock can be re-enabled prior to
+    // preview being re-started, to keep the exposure values from the previous
+    // lock. In conjunction with exposure compensation, this allows for
+    // capturing multi-exposure brackets with known relative exposure
+    // values. Locking auto-exposure after open but before the first cal to
+    // startPreview may result in severly over- or under-exposed images.  The
+    // driver may independently enable the AE lock after auto-focus
+    // completes. If it does so, this key must have its value updated to reflect
+    // the lock's existence. Applications are free to release such a lock, to
+    // re-enable AE without restarting preview.
+    static const char KEY_AUTO_EXPOSURE_LOCK[];
+    // Whether locking the auto-exposure is supported. "true" means it is, and
+    // "false" or this key not existing means it is not supported.
+    static const char KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[];
     // The maximum number of metering areas supported. This is the maximum
     // length of KEY_METERING_AREAS.
     // Example value: "0" or "2". Read only.
@@ -428,6 +447,7 @@
 
     // Value for KEY_ZOOM_SUPPORTED or KEY_SMOOTH_ZOOM_SUPPORTED.
     static const char TRUE[];
+    static const char FALSE[];
 
     // Value for KEY_FOCUS_DISTANCES.
     static const char FOCUS_DISTANCE_INFINITY[];
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index fe9b049..c77bc4c 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -45,20 +45,20 @@
     SurfaceTextureClient(const SurfaceTextureClient& rhs);
 
     // ANativeWindow hooks
-    static int cancelBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
-    static int dequeueBuffer(ANativeWindow* window, android_native_buffer_t** buffer);
-    static int lockBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
+    static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+    static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
+    static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
     static int perform(ANativeWindow* window, int operation, ...);
-    static int query(ANativeWindow* window, int what, int* value);
-    static int queueBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
+    static int query(const ANativeWindow* window, int what, int* value);
+    static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
     static int setSwapInterval(ANativeWindow* window, int interval);
 
-    int cancelBuffer(android_native_buffer_t* buffer);
-    int dequeueBuffer(android_native_buffer_t** buffer);
-    int lockBuffer(android_native_buffer_t* buffer);
+    int cancelBuffer(ANativeWindowBuffer* buffer);
+    int dequeueBuffer(ANativeWindowBuffer** buffer);
+    int lockBuffer(ANativeWindowBuffer* buffer);
     int perform(int operation, va_list args);
-    int query(int what, int* value);
-    int queueBuffer(android_native_buffer_t* buffer);
+    int query(int what, int* value) const;
+    int queueBuffer(ANativeWindowBuffer* buffer);
     int setSwapInterval(int interval);
 
     int dispatchConnect(va_list args);
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index 3e343e0..28f305d 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -52,6 +52,7 @@
     METADATA_KEY_VIDEO_WIDTH     = 18,
     METADATA_KEY_VIDEO_HEIGHT    = 19,
     METADATA_KEY_BITRATE         = 20,
+    METADATA_KEY_TIMED_TEXT_LANGUAGES      = 21,
 
     // Add more here...
 };
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 241626c..cfa4cfd 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -125,6 +125,9 @@
     MEDIA_PLAYER_PLAYBACK_COMPLETE  = 1 << 7
 };
 
+enum media_set_parameter_keys {
+    KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX = 1000,
+};
 // ----------------------------------------------------------------------------
 // ref-counted object for callbacks
 class MediaPlayerListener: virtual public RefBase
diff --git a/include/media/stagefright/AACWriter.h b/include/media/stagefright/AACWriter.h
new file mode 100644
index 0000000..fa3ab8a
--- /dev/null
+++ b/include/media/stagefright/AACWriter.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 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 AAC_WRITER_H_
+#define AAC_WRITER_H_
+
+#include <media/stagefright/MediaWriter.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct MediaSource;
+struct MetaData;
+
+struct AACWriter : public MediaWriter {
+    AACWriter(const char *filename);
+    AACWriter(int fd);
+
+    status_t initCheck() const;
+
+    virtual status_t addSource(const sp<MediaSource> &source);
+    virtual bool reachedEOS();
+    virtual status_t start(MetaData *params = NULL);
+    virtual status_t stop();
+    virtual status_t pause();
+
+protected:
+    virtual ~AACWriter();
+
+private:
+    enum {
+        kAdtsHeaderLength = 7,     // # of bytes for the adts header
+        kSamplesPerFrame  = 1024,  // # of samples in a frame
+    };
+
+    int   mFd;
+    status_t mInitCheck;
+    sp<MediaSource> mSource;
+    bool mStarted;
+    volatile bool mPaused;
+    volatile bool mResumed;
+    volatile bool mDone;
+    volatile bool mReachedEOS;
+    pthread_t mThread;
+    int64_t mEstimatedSizeBytes;
+    int64_t mEstimatedDurationUs;
+    int32_t mChannelCount;
+    int32_t mSampleRate;
+    int32_t mFrameDurationUs;
+
+    static void *ThreadWrapper(void *);
+    status_t threadFunc();
+    bool exceedsFileSizeLimit();
+    bool exceedsFileDurationLimit();
+    status_t writeAdtsHeader(uint32_t frameLength);
+
+    DISALLOW_EVIL_CONSTRUCTORS(AACWriter);
+};
+
+}  // namespace android
+
+#endif  // AAC_WRITER_H_
diff --git a/include/media/stagefright/HardwareAPI.h b/include/media/stagefright/HardwareAPI.h
index d1ecaaf..946a0aa 100644
--- a/include/media/stagefright/HardwareAPI.h
+++ b/include/media/stagefright/HardwareAPI.h
@@ -84,7 +84,7 @@
     OMX_U32 nPortIndex;
     OMX_PTR pAppPrivate;
     OMX_BUFFERHEADERTYPE **bufferHeader;
-    const sp<android_native_buffer_t>& nativeBuffer;
+    const sp<ANativeWindowBuffer>& nativeBuffer;
 };
 
 // A pointer to this struct is passed to OMX_GetParameter when the extension
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 6a21627..5e471c1 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -49,6 +49,8 @@
 
 extern const char *MEDIA_MIMETYPE_CONTAINER_WVM;
 
+extern const char *MEDIA_MIMETYPE_TEXT_3GPP;
+
 }  // namespace android
 
 #endif  // MEDIA_DEFS_H_
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index f7f2235..4044c5d 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -114,6 +114,9 @@
 
     // An indication that a video buffer has been rendered.
     kKeyRendered          = 'rend',  // bool (int32_t)
+
+    // The language code for this media
+    kKeyMediaLanguage     = 'lang',  // cstring
 };
 
 enum {
diff --git a/include/private/opengles/gl_context.h b/include/private/opengles/gl_context.h
index 72416c1..6b1fa77 100644
--- a/include/private/opengles/gl_context.h
+++ b/include/private/opengles/gl_context.h
@@ -31,8 +31,6 @@
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
-struct android_native_buffer_t;
-
 namespace android {
 
 
@@ -603,13 +601,6 @@
     void (*renderTriangle)(GL, vertex_t*, vertex_t*, vertex_t*);
 };
 
-struct copybits_context_t {
-    // A handle to the blit engine, if it exists, else NULL.
-    int32_t                 minScale;
-    int32_t                 maxScale;
-    android_native_buffer_t* drawSurfaceBuffer;
-};
-
 struct ogles_context_t {
     context_t               rasterizer;
     array_machine_t         arrays         __attribute__((aligned(32)));
@@ -634,13 +625,6 @@
     EGLSurfaceManager*      surfaceManager;
     EGLBufferObjectManager* bufferObjectManager;
 
-    // copybits is only used if LIBAGL_USE_GRALLOC_COPYBITS is
-    // defined, but it is always present because ogles_context_t is a public
-    // struct that is used by clients of libagl. We want the size and offsets
-    // to stay the same, whether or not LIBAGL_USE_GRALLOC_COPYBITS is defined.
-
-    copybits_context_t      copybits;
-
     GLenum                  error;
 
     static inline ogles_context_t* get() {
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index 3923e61..ab30f45 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -202,18 +202,18 @@
      *  ANativeWindow hooks
      */
     static int setSwapInterval(ANativeWindow* window, int interval);
-    static int dequeueBuffer(ANativeWindow* window, android_native_buffer_t** buffer);
-    static int cancelBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
-    static int lockBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
-    static int queueBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
-    static int query(ANativeWindow* window, int what, int* value);
+    static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
+    static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+    static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+    static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+    static int query(const ANativeWindow* window, int what, int* value);
     static int perform(ANativeWindow* 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 cancelBuffer(android_native_buffer_t* buffer);
-    int query(int what, int* value);
+    int dequeueBuffer(ANativeWindowBuffer** buffer);
+    int lockBuffer(ANativeWindowBuffer* buffer);
+    int queueBuffer(ANativeWindowBuffer* buffer);
+    int cancelBuffer(ANativeWindowBuffer* buffer);
+    int query(int what, int* value) const;
     int perform(int operation, va_list args);
 
     void dispatch_setUsage(va_list args);
diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h
index 16117ad..302d012 100644
--- a/include/ui/FramebufferNativeWindow.h
+++ b/include/ui/FramebufferNativeWindow.h
@@ -67,10 +67,10 @@
     friend class LightRefBase<FramebufferNativeWindow>;    
     ~FramebufferNativeWindow(); // this class cannot be overloaded
     static int setSwapInterval(ANativeWindow* window, int interval);
-    static int dequeueBuffer(ANativeWindow* window, android_native_buffer_t** buffer);
-    static int lockBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
-    static int queueBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
-    static int query(ANativeWindow* window, int what, int* value);
+    static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
+    static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+    static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+    static int query(const ANativeWindow* window, int what, int* value);
     static int perform(ANativeWindow* window, int operation, ...);
     
     framebuffer_device_t* fbDev;
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index 02d6f8f..370253a 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -26,7 +26,7 @@
 #include <utils/Flattenable.h>
 #include <pixelflinger/pixelflinger.h>
 
-struct android_native_buffer_t;
+struct ANativeWindowBuffer;
 
 namespace android {
 
@@ -38,7 +38,7 @@
 
 class GraphicBuffer
     : public EGLNativeBase<
-        android_native_buffer_t, 
+        ANativeWindowBuffer,
         GraphicBuffer, 
         LightRefBase<GraphicBuffer> >, public Flattenable
 {
@@ -74,8 +74,8 @@
     GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage,
             uint32_t stride, native_handle_t* handle, bool keepOwnership);
 
-    // create a buffer from an existing android_native_buffer_t
-    GraphicBuffer(android_native_buffer_t* buffer, bool keepOwnership);
+    // create a buffer from an existing ANativeWindowBuffer
+    GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership);
 
     // return status
     status_t initCheck() const;
@@ -94,7 +94,7 @@
     status_t lock(GGLSurface* surface, uint32_t usage);
     status_t unlock();
 
-    android_native_buffer_t* getNativeBuffer() const;
+    ANativeWindowBuffer* getNativeBuffer() const;
     
     void setIndex(int index);
     int getIndex() const;
@@ -149,7 +149,7 @@
 
     // If we're wrapping another buffer then this reference will make sure it
     // doesn't get freed.
-    sp<android_native_buffer_t> mWrappedBuffer;
+    sp<ANativeWindowBuffer> mWrappedBuffer;
 };
 
 }; // namespace android
diff --git a/include/ui/android_native_buffer.h b/include/ui/android_native_buffer.h
index 402843e..b6e1db4 100644
--- a/include/ui/android_native_buffer.h
+++ b/include/ui/android_native_buffer.h
@@ -19,53 +19,4 @@
 
 #include <ui/egl/android_natives.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*****************************************************************************/
-
-typedef struct android_native_buffer_t
-{
-#ifdef __cplusplus
-    android_native_buffer_t() { 
-        common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
-        common.version = sizeof(android_native_buffer_t);
-        memset(common.reserved, 0, sizeof(common.reserved));
-    }
-
-    // Implement the methods that sp<android_native_buffer_t> expects so that it
-    // can be used to automatically refcount android_native_buffer_t's.
-    void incStrong(const void* id) const {
-        common.incRef(const_cast<android_native_base_t*>(&common));
-    }
-    void decStrong(const void* id) const {
-        common.decRef(const_cast<android_native_base_t*>(&common));
-    }
-#endif
-
-    struct android_native_base_t common;
-
-    int width;
-    int height;
-    int stride;
-    int format;
-    int usage;
-    
-    void* reserved[2];
-
-    buffer_handle_t handle;
-
-    void* reserved_proc[8];
-} android_native_buffer_t;
-
-
-/*****************************************************************************/
-
-#ifdef __cplusplus
-}
-#endif
-
-/*****************************************************************************/
-
 #endif /* ANDROID_ANDROID_NATIVES_PRIV_H */
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index 0a6e4fb..9ac50a5 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -21,400 +21,9 @@
 #include <string.h>
 
 #include <hardware/gralloc.h>
-
+#include <system/window.h>
+// FIXME: remove this header, it's for legacy use.  native_window is pulled from frameworks/base/native/include/android/
 #include <android/native_window.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*****************************************************************************/
-
-#define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d) \
-    (((unsigned)(a)<<24)|((unsigned)(b)<<16)|((unsigned)(c)<<8)|(unsigned)(d))
-
-#define ANDROID_NATIVE_WINDOW_MAGIC \
-    ANDROID_NATIVE_MAKE_CONSTANT('_','w','n','d')
-
-#define ANDROID_NATIVE_BUFFER_MAGIC \
-    ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r')
-
-// ---------------------------------------------------------------------------
-
-struct android_native_buffer_t;
-
-typedef struct android_native_rect_t
-{
-    int32_t left;
-    int32_t top;
-    int32_t right;
-    int32_t bottom;
-} android_native_rect_t;
-
-// ---------------------------------------------------------------------------
-
-typedef struct android_native_base_t
-{
-    /* a magic value defined by the actual EGL native type */
-    int magic;
-
-    /* the sizeof() of the actual EGL native type */
-    int version;
-
-    void* reserved[4];
-
-    /* reference-counting interface */
-    void (*incRef)(struct android_native_base_t* base);
-    void (*decRef)(struct android_native_base_t* base);
-} android_native_base_t;
-
-// ---------------------------------------------------------------------------
-
-/* attributes queriable with query() */
-enum {
-    NATIVE_WINDOW_WIDTH     = 0,
-    NATIVE_WINDOW_HEIGHT,
-    NATIVE_WINDOW_FORMAT,
-
-    /* The minimum number of buffers that must remain un-dequeued after a buffer
-     * has been queued.  This value applies only if set_buffer_count was used to
-     * override the number of buffers and if a buffer has since been queued.
-     * Users of the set_buffer_count ANativeWindow method should query this
-     * value before calling set_buffer_count.  If it is necessary to have N
-     * buffers simultaneously dequeued as part of the steady-state operation,
-     * and this query returns M then N+M buffers should be requested via
-     * native_window_set_buffer_count.
-     *
-     * Note that this value does NOT apply until a single buffer has been
-     * queued.  In particular this means that it is possible to:
-     *
-     * 1. Query M = min undequeued buffers
-     * 2. Set the buffer count to N + M
-     * 3. Dequeue all N + M buffers
-     * 4. Cancel M buffers
-     * 5. Queue, dequeue, queue, dequeue, ad infinitum
-     */
-    NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
-
-    /* Check whether queueBuffer operations on the ANativeWindow send the buffer
-     * to the window compositor.  The query sets the returned 'value' argument
-     * to 1 if the ANativeWindow DOES send queued buffers directly to the window
-     * compositor and 0 if the buffers do not go directly to the window
-     * compositor.
-     *
-     * This can be used to determine whether protected buffer content should be
-     * sent to the ANativeWindow.  Note, however, that a result of 1 does NOT
-     * indicate that queued buffers will be protected from applications or users
-     * capturing their contents.  If that behavior is desired then some other
-     * mechanism (e.g. the GRALLOC_USAGE_PROTECTED flag) should be used in
-     * conjunction with this query.
-     */
-    NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
-
-    /* Get the concrete type of a ANativeWindow.  See below for the list of
-     * possible return values.
-     *
-     * This query should not be used outside the Android framework and will
-     * likely be removed in the near future.
-     */
-    NATIVE_WINDOW_CONCRETE_TYPE,
-};
-
-/* valid operations for the (*perform)() hook */
-enum {
-    NATIVE_WINDOW_SET_USAGE  = 0,
-    NATIVE_WINDOW_CONNECT,
-    NATIVE_WINDOW_DISCONNECT,
-    NATIVE_WINDOW_SET_CROP,
-    NATIVE_WINDOW_SET_BUFFER_COUNT,
-    NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
-    NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
-    NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP,
-};
-
-/* parameter for NATIVE_WINDOW_[DIS]CONNECT */
-enum {
-    NATIVE_WINDOW_API_EGL = 1
-};
-
-/* parameter for NATIVE_WINDOW_SET_BUFFERS_TRANSFORM */
-enum {
-    /* flip source image horizontally */
-    NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H ,
-    /* flip source image vertically */
-    NATIVE_WINDOW_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
-    /* rotate source image 90 degrees clock-wise */
-    NATIVE_WINDOW_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
-    /* rotate source image 180 degrees */
-    NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
-    /* rotate source image 270 degrees clock-wise */
-    NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
-};
-
-/* values returned by the NATIVE_WINDOW_CONCRETE_TYPE query */
-enum {
-    NATIVE_WINDOW_FRAMEBUFFER,                  // FramebufferNativeWindow
-    NATIVE_WINDOW_SURFACE,                      // Surface
-    NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT,       // SurfaceTextureClient
-};
-
-/* parameter for NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
- *
- * Special timestamp value to indicate that timestamps should be auto-generated
- * by the native window when queueBuffer is called.  This is equal to INT64_MIN,
- * defined directly to avoid problems with C99/C++ inclusion of stdint.h.
- */
-const int64_t NATIVE_WINDOW_TIMESTAMP_AUTO = (-9223372036854775807LL-1);
-
-struct ANativeWindow
-{
-#ifdef __cplusplus
-    ANativeWindow()
-        : flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0)
-    {
-        common.magic = ANDROID_NATIVE_WINDOW_MAGIC;
-        common.version = sizeof(ANativeWindow);
-        memset(common.reserved, 0, sizeof(common.reserved));
-    }
-
-    // Implement the methods that sp<ANativeWindow> expects so that it
-    // can be used to automatically refcount ANativeWindow's.
-    void incStrong(const void* id) const {
-        common.incRef(const_cast<android_native_base_t*>(&common));
-    }
-    void decStrong(const void* id) const {
-        common.decRef(const_cast<android_native_base_t*>(&common));
-    }
-#endif
-    
-    struct android_native_base_t common;
-
-    /* flags describing some attributes of this surface or its updater */
-    const uint32_t flags;
-    
-    /* min swap interval supported by this updated */
-    const int   minSwapInterval;
-
-    /* max swap interval supported by this updated */
-    const int   maxSwapInterval;
-
-    /* horizontal and vertical resolution in DPI */
-    const float xdpi;
-    const float ydpi;
-
-    /* Some storage reserved for the OEM's driver. */
-    intptr_t    oem[4];
-        
-
-    /*
-     * Set the swap interval for this surface.
-     * 
-     * Returns 0 on success or -errno on error.
-     */
-    int     (*setSwapInterval)(struct ANativeWindow* window,
-                int interval);
-    
-    /*
-     * hook called by EGL to acquire a buffer. After this call, the buffer
-     * is not locked, so its content cannot be modified.
-     * this call may block if no buffers are available.
-     * 
-     * Returns 0 on success or -errno on error.
-     */
-    int     (*dequeueBuffer)(struct ANativeWindow* window,
-                struct android_native_buffer_t** buffer);
-
-    /*
-     * hook called by EGL to lock a buffer. This MUST be called before modifying
-     * the content of a buffer. The buffer must have been acquired with 
-     * dequeueBuffer first.
-     * 
-     * Returns 0 on success or -errno on error.
-     */
-    int     (*lockBuffer)(struct ANativeWindow* window,
-                struct android_native_buffer_t* buffer);
-   /*
-    * hook called by EGL when modifications to the render buffer are done. 
-    * This unlocks and post the buffer.
-    * 
-    * Buffers MUST be queued in the same order than they were dequeued.
-    * 
-    * Returns 0 on success or -errno on error.
-    */
-    int     (*queueBuffer)(struct ANativeWindow* window,
-                struct android_native_buffer_t* buffer);
-
-    /*
-     * hook used to retrieve information about the native window.
-     * 
-     * Returns 0 on success or -errno on error.
-     */
-    int     (*query)(struct ANativeWindow* window,
-                int what, int* value);
-    
-    /*
-     * hook used to perform various operations on the surface.
-     * (*perform)() is a generic mechanism to add functionality to
-     * ANativeWindow while keeping backward binary compatibility.
-     * 
-     * This hook should not be called directly, instead use the helper functions
-     * defined below.
-     * 
-     *  (*perform)() returns -ENOENT if the 'what' parameter is not supported
-     *  by the surface's implementation.
-     *
-     * The valid operations are:
-     *     NATIVE_WINDOW_SET_USAGE
-     *     NATIVE_WINDOW_CONNECT
-     *     NATIVE_WINDOW_DISCONNECT
-     *     NATIVE_WINDOW_SET_CROP
-     *     NATIVE_WINDOW_SET_BUFFER_COUNT
-     *     NATIVE_WINDOW_SET_BUFFERS_GEOMETRY
-     *     NATIVE_WINDOW_SET_BUFFERS_TRANSFORM
-     *     NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
-     *
-     */
-    
-    int     (*perform)(struct ANativeWindow* window,
-                int operation, ... );
-    
-    /*
-     * hook used to cancel a buffer that has been dequeued.
-     * No synchronization is performed between dequeue() and cancel(), so
-     * either external synchronization is needed, or these functions must be
-     * called from the same thread.
-     */
-    int     (*cancelBuffer)(struct ANativeWindow* window,
-                struct android_native_buffer_t* buffer);
-
-
-    void* reserved_proc[2];
-};
-
-// Backwards compatibility...  please switch to ANativeWindow.
-typedef struct ANativeWindow android_native_window_t;
-
-/*
- *  native_window_set_usage(..., 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.
- */
-
-static inline int native_window_set_usage(
-        ANativeWindow* window, int usage)
-{
-    return window->perform(window, NATIVE_WINDOW_SET_USAGE, usage);
-}
-
-/*
- * native_window_connect(..., NATIVE_WINDOW_API_EGL)
- * Must be called by EGL when the window is made current.
- * Returns -EINVAL if for some reason the window cannot be connected, which
- * can happen if it's connected to some other API.
- */
-static inline int native_window_connect(
-        ANativeWindow* window, int api)
-{
-    return window->perform(window, NATIVE_WINDOW_CONNECT, api);
-}
-
-/*
- * native_window_disconnect(..., NATIVE_WINDOW_API_EGL)
- * Must be called by EGL when the window is made not current.
- * An error is returned if for instance the window wasn't connected in the
- * first place.
- */
-static inline int native_window_disconnect(
-        ANativeWindow* window, int api)
-{
-    return window->perform(window, NATIVE_WINDOW_DISCONNECT, api);
-}
-
-/*
- * native_window_set_crop(..., crop)
- * Sets which region of the next queued buffers needs to be considered.
- * A buffer's crop region is scaled to match the surface's size.
- *
- * The specified crop region applies to all buffers queued after it is called.
- *
- * if 'crop' is NULL, subsequently queued buffers won't be cropped.
- *
- * An error is returned if for instance the crop region is invalid,
- * out of the buffer's bound or if the window is invalid.
- */
-static inline int native_window_set_crop(
-        ANativeWindow* window,
-        android_native_rect_t const * crop)
-{
-    return window->perform(window, NATIVE_WINDOW_SET_CROP, crop);
-}
-
-/*
- * native_window_set_buffer_count(..., count)
- * Sets the number of buffers associated with this native window.
- */
-static inline int native_window_set_buffer_count(
-        ANativeWindow* window,
-        size_t bufferCount)
-{
-    return window->perform(window, NATIVE_WINDOW_SET_BUFFER_COUNT, bufferCount);
-}
-
-/*
- * native_window_set_buffers_geometry(..., int w, int h, int format)
- * All buffers dequeued after this call will have the geometry specified.
- * In particular, all buffers will have a fixed-size, independent form the
- * native-window size. They will be appropriately scaled to the window-size
- * upon composition.
- *
- * If all parameters are 0, the normal behavior is restored. That is,
- * dequeued buffers following this call will be sized to the window's size.
- *
- * Calling this function will reset the window crop to a NULL value, which
- * disables cropping of the buffers.
- */
-static inline int native_window_set_buffers_geometry(
-        ANativeWindow* window,
-        int w, int h, int format)
-{
-    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
-            w, h, format);
-}
-
-/*
- * native_window_set_buffers_transform(..., int transform)
- * All buffers queued after this call will be displayed transformed according
- * to the transform parameter specified.
- */
-static inline int native_window_set_buffers_transform(
-        ANativeWindow* window,
-        int transform)
-{
-    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
-            transform);
-}
-
-/*
- * native_window_set_buffers_timestamp(..., int64_t timestamp)
- * All buffers queued after this call will be associated with the timestamp
- * parameter specified. If the timestamp is set to NATIVE_WINDOW_TIMESTAMP_AUTO
- * (the default), timestamps will be generated automatically when queueBuffer is
- * called. The timestamp is measured in nanoseconds, and must be monotonically
- * increasing.
- */
-static inline int native_window_set_buffers_timestamp(
-        ANativeWindow* window,
-        int64_t timestamp)
-{
-    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP,
-            timestamp);
-}
-
 // ---------------------------------------------------------------------------
 
 /* FIXME: this is legacy for pixmaps */
@@ -437,13 +46,6 @@
 /*****************************************************************************/
 
 #ifdef __cplusplus
-}
-#endif
-
-
-/*****************************************************************************/
-
-#ifdef __cplusplus
 
 #include <utils/RefBase.h>
 
diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp
index 214cd4d..4f3da40 100644
--- a/libs/camera/CameraParameters.cpp
+++ b/libs/camera/CameraParameters.cpp
@@ -68,6 +68,8 @@
 const char CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION[] = "max-exposure-compensation";
 const char CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION[] = "min-exposure-compensation";
 const char CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP[] = "exposure-compensation-step";
+const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK[] = "auto-exposure-lock";
+const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[] = "auto-exposure-lock-supported";
 const char CameraParameters::KEY_MAX_NUM_METERING_AREAS[] = "max-num-metering-areas";
 const char CameraParameters::KEY_METERING_AREAS[] = "metering-areas";
 const char CameraParameters::KEY_ZOOM[] = "zoom";
@@ -82,6 +84,7 @@
 const char CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[] = "preferred-preview-size-for-video";
 
 const char CameraParameters::TRUE[] = "true";
+const char CameraParameters::FALSE[] = "false";
 const char CameraParameters::FOCUS_DISTANCE_INFINITY[] = "Infinity";
 
 // Values for white balance settings.
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 44d9b4b..0c5767b 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -513,32 +513,32 @@
 }
 
 int Surface::dequeueBuffer(ANativeWindow* window, 
-        android_native_buffer_t** buffer) {
+        ANativeWindowBuffer** buffer) {
     Surface* self = getSelf(window);
     return self->dequeueBuffer(buffer);
 }
 
 int Surface::cancelBuffer(ANativeWindow* window,
-        android_native_buffer_t* buffer) {
+        ANativeWindowBuffer* buffer) {
     Surface* self = getSelf(window);
     return self->cancelBuffer(buffer);
 }
 
 int Surface::lockBuffer(ANativeWindow* window, 
-        android_native_buffer_t* buffer) {
+        ANativeWindowBuffer* buffer) {
     Surface* self = getSelf(window);
     return self->lockBuffer(buffer);
 }
 
 int Surface::queueBuffer(ANativeWindow* window, 
-        android_native_buffer_t* buffer) {
+        ANativeWindowBuffer* buffer) {
     Surface* self = getSelf(window);
     return self->queueBuffer(buffer);
 }
 
-int Surface::query(ANativeWindow* window, 
+int Surface::query(const ANativeWindow* window,
         int what, int* value) {
-    Surface* self = getSelf(window);
+    const Surface* self = getSelf(window);
     return self->query(what, value);
 }
 
@@ -570,7 +570,7 @@
     return newNeewBuffer;
 }
 
-int Surface::dequeueBuffer(android_native_buffer_t** buffer)
+int Surface::dequeueBuffer(ANativeWindowBuffer** buffer)
 {
     status_t err = validate();
     if (err != NO_ERROR)
@@ -624,7 +624,7 @@
     return err;
 }
 
-int Surface::cancelBuffer(android_native_buffer_t* buffer)
+int Surface::cancelBuffer(ANativeWindowBuffer* buffer)
 {
     status_t err = validate(true);
     switch (err) {
@@ -651,7 +651,7 @@
 }
 
 
-int Surface::lockBuffer(android_native_buffer_t* buffer)
+int Surface::lockBuffer(ANativeWindowBuffer* buffer)
 {
     status_t err = validate();
     if (err != NO_ERROR)
@@ -670,7 +670,7 @@
     return err;
 }
 
-int Surface::queueBuffer(android_native_buffer_t* buffer)
+int Surface::queueBuffer(ANativeWindowBuffer* buffer)
 {
     status_t err = validate();
     if (err != NO_ERROR)
@@ -697,7 +697,7 @@
     return err;
 }
 
-int Surface::query(int what, int* value)
+int Surface::query(int what, int* value) const
 {
     switch (what) {
     case NATIVE_WINDOW_WIDTH:
@@ -969,7 +969,7 @@
     // we're intending to do software rendering from this point
     setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
 
-    android_native_buffer_t* out;
+    ANativeWindowBuffer* out;
     status_t err = dequeueBuffer(&out);
     LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
     if (err == NO_ERROR) {
@@ -1063,7 +1063,7 @@
     if (idx < 0) {
         // The buffer doesn't have an index set.  See if the handle the same as
         // one of the buffers for which we do know the index.  This can happen
-        // e.g. if GraphicBuffer is used to wrap an android_native_buffer_t that
+        // e.g. if GraphicBuffer is used to wrap an ANativeWindowBuffer that
         // was dequeued from an ANativeWindow.
         for (size_t i = 0; i < mBuffers.size(); i++) {
             if (mBuffers[i] != 0 && buffer->handle == mBuffers[i]->handle) {
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index f4b2416..ec6da43 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -53,31 +53,32 @@
 }
 
 int SurfaceTextureClient::dequeueBuffer(ANativeWindow* window,
-        android_native_buffer_t** buffer) {
+        ANativeWindowBuffer** buffer) {
     SurfaceTextureClient* c = getSelf(window);
     return c->dequeueBuffer(buffer);
 }
 
 int SurfaceTextureClient::cancelBuffer(ANativeWindow* window,
-        android_native_buffer_t* buffer) {
+        ANativeWindowBuffer* buffer) {
     SurfaceTextureClient* c = getSelf(window);
     return c->cancelBuffer(buffer);
 }
 
 int SurfaceTextureClient::lockBuffer(ANativeWindow* window,
-        android_native_buffer_t* buffer) {
+        ANativeWindowBuffer* buffer) {
     SurfaceTextureClient* c = getSelf(window);
     return c->lockBuffer(buffer);
 }
 
 int SurfaceTextureClient::queueBuffer(ANativeWindow* window,
-        android_native_buffer_t* buffer) {
+        ANativeWindowBuffer* buffer) {
     SurfaceTextureClient* c = getSelf(window);
     return c->queueBuffer(buffer);
 }
 
-int SurfaceTextureClient::query(ANativeWindow* window, int what, int* value) {
-    SurfaceTextureClient* c = getSelf(window);
+int SurfaceTextureClient::query(const ANativeWindow* window,
+                                int what, int* value) {
+    const SurfaceTextureClient* c = getSelf(window);
     return c->query(what, value);
 }
 
@@ -160,7 +161,7 @@
     return BAD_VALUE;
 }
 
-int SurfaceTextureClient::query(int what, int* value) {
+int SurfaceTextureClient::query(int what, int* value) const {
     LOGV("SurfaceTextureClient::query");
     Mutex::Autolock lock(mMutex);
     switch (what) {
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index db781de..753e933 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -113,7 +113,7 @@
 
 TEST_F(SurfaceTextureClientTest, DefaultGeometryValues) {
     sp<ANativeWindow> anw(mSTC);
-    android_native_buffer_t* buf;
+    ANativeWindowBuffer* buf;
     ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
     EXPECT_EQ(1, buf->width);
     EXPECT_EQ(1, buf->height);
@@ -123,7 +123,7 @@
 
 TEST_F(SurfaceTextureClientTest, BufferGeometryCanBeSet) {
     sp<ANativeWindow> anw(mSTC);
-    android_native_buffer_t* buf;
+    ANativeWindowBuffer* buf;
     EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, PIXEL_FORMAT_RGB_565));
     ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
     EXPECT_EQ(16, buf->width);
@@ -134,7 +134,7 @@
 
 TEST_F(SurfaceTextureClientTest, BufferGeometryDefaultSizeSetFormat) {
     sp<ANativeWindow> anw(mSTC);
-    android_native_buffer_t* buf;
+    ANativeWindowBuffer* buf;
     EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, PIXEL_FORMAT_RGB_565));
     ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
     EXPECT_EQ(1, buf->width);
@@ -145,7 +145,7 @@
 
 TEST_F(SurfaceTextureClientTest, BufferGeometrySetSizeDefaultFormat) {
     sp<ANativeWindow> anw(mSTC);
-    android_native_buffer_t* buf;
+    ANativeWindowBuffer* buf;
     EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, 0));
     ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
     EXPECT_EQ(16, buf->width);
@@ -156,7 +156,7 @@
 
 TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeUnset) {
     sp<ANativeWindow> anw(mSTC);
-    android_native_buffer_t* buf;
+    ANativeWindowBuffer* buf;
     EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, 0));
     ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
     EXPECT_EQ(16, buf->width);
@@ -173,7 +173,7 @@
 
 TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeChangedWithoutFormat) {
     sp<ANativeWindow> anw(mSTC);
-    android_native_buffer_t* buf;
+    ANativeWindowBuffer* buf;
     EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, PIXEL_FORMAT_RGB_565));
     ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
     EXPECT_EQ(1, buf->width);
@@ -191,7 +191,7 @@
 TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSize) {
     sp<ANativeWindow> anw(mSTC);
     sp<SurfaceTexture> st(mST);
-    android_native_buffer_t* buf;
+    ANativeWindowBuffer* buf;
     EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8));
     ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
     EXPECT_EQ(16, buf->width);
@@ -203,7 +203,7 @@
 TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeAfterDequeue) {
     sp<ANativeWindow> anw(mSTC);
     sp<SurfaceTexture> st(mST);
-    android_native_buffer_t* buf[2];
+    ANativeWindowBuffer* buf[2];
     ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
     ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
     EXPECT_NE(buf[0], buf[1]);
@@ -224,7 +224,7 @@
 TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeVsGeometry) {
     sp<ANativeWindow> anw(mSTC);
     sp<SurfaceTexture> st(mST);
-    android_native_buffer_t* buf[2];
+    ANativeWindowBuffer* buf[2];
     EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8));
     ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
     ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 6c71343..8747ba5 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -476,7 +476,7 @@
     ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
             GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
 
-    android_native_buffer_t* anb;
+    ANativeWindowBuffer* anb;
     ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
     ASSERT_TRUE(anb != NULL);
 
@@ -524,7 +524,7 @@
     ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
             GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
 
-    android_native_buffer_t* anb;
+    ANativeWindowBuffer* anb;
     ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
     ASSERT_TRUE(anb != NULL);
 
@@ -583,7 +583,7 @@
 
         ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop));
 
-        android_native_buffer_t* anb;
+        ANativeWindowBuffer* anb;
         ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
         ASSERT_TRUE(anb != NULL);
 
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 440a48b..35c8640 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -93,7 +93,7 @@
     ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(),
             GRALLOC_USAGE_PROTECTED));
     ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3));
-    android_native_buffer_t* buf = 0;
+    ANativeWindowBuffer* buf = 0;
     for (int i = 0; i < 4; i++) {
         // Loop to make sure SurfaceFlinger has retired a protected buffer.
         ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf));
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index faecadd..596781e 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -62,8 +62,10 @@
 static const GLsizei gMeshStride = sizeof(TextureVertex);
 static const GLsizei gVertexStride = sizeof(Vertex);
 static const GLsizei gAlphaVertexStride = sizeof(AlphaVertex);
+static const GLsizei gAAVertexStride = sizeof(AAVertex);
 static const GLsizei gMeshTextureOffset = 2 * sizeof(float);
-static const GLsizei gVertexAlphaOffset = 2 * sizeof(float);
+static const GLsizei gVertexAAWidthOffset = 2 * sizeof(float);
+static const GLsizei gVertexAALengthOffset = 3 * sizeof(float);
 static const GLsizei gMeshCount = 4;
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 34dda9a..f8582d8 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -177,6 +177,331 @@
 void DisplayList::init() {
 }
 
+/**
+ * This function is a simplified version of replay(), where we simply retrieve and log the
+ * display list. This function should remain in sync with the replay() function.
+ */
+void DisplayList::output(OpenGLRenderer& renderer, uint32_t level) {
+    TextContainer text;
+
+    uint32_t count = (level + 1) * 2;
+    char indent[count + 1];
+    for (uint32_t i = 0; i < count; i++) {
+        indent[i] = ' ';
+    }
+    indent[count] = '\0';
+    LOGD("%sStart display list (%p)", (char*) indent + 2, this);
+
+    int saveCount = renderer.getSaveCount() - 1;
+
+    mReader.rewind();
+
+    while (!mReader.eof()) {
+        int op = mReader.readInt();
+
+        switch (op) {
+            case DrawGLFunction: {
+                Functor *functor = (Functor *) getInt();
+                LOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor);
+            }
+            break;
+            case Save: {
+                int rendererNum = getInt();
+                LOGD("%s%s %d", (char*) indent, OP_NAMES[op], rendererNum);
+            }
+            break;
+            case Restore: {
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case RestoreToCount: {
+                int restoreCount = saveCount + getInt();
+                LOGD("%s%s %d", (char*) indent, OP_NAMES[op], restoreCount);
+            }
+            break;
+            case SaveLayer: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                SkPaint* paint = getPaint();
+                int flags = getInt();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent,
+                    OP_NAMES[op], f1, f2, f3, f4, paint, flags);
+            }
+            break;
+            case SaveLayerAlpha: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                int alpha = getInt();
+                int flags = getInt();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent,
+                    OP_NAMES[op], f1, f2, f3, f4, alpha, flags);
+            }
+            break;
+            case Translate: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], f1, f2);
+            }
+            break;
+            case Rotate: {
+                float rotation = getFloat();
+                LOGD("%s%s %.2f", (char*) indent, OP_NAMES[op], rotation);
+            }
+            break;
+            case Scale: {
+                float sx = getFloat();
+                float sy = getFloat();
+                LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy);
+            }
+            break;
+            case Skew: {
+                float sx = getFloat();
+                float sy = getFloat();
+                LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy);
+            }
+            break;
+            case SetMatrix: {
+                SkMatrix* matrix = getMatrix();
+                LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix);
+            }
+            break;
+            case ConcatMatrix: {
+                SkMatrix* matrix = getMatrix();
+                LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix);
+            }
+            break;
+            case ClipRect: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                int regionOp = getInt();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op],
+                    f1, f2, f3, f4, regionOp);
+            }
+            break;
+            case DrawDisplayList: {
+                DisplayList* displayList = getDisplayList();
+                uint32_t width = getUInt();
+                uint32_t height = getUInt();
+                LOGD("%s%s %p, %dx%d, %d", (char*) indent, OP_NAMES[op],
+                    displayList, width, height, level + 1);
+                renderer.outputDisplayList(displayList, level + 1);
+            }
+            break;
+            case DrawLayer: {
+                Layer* layer = (Layer*) getInt();
+                float x = getFloat();
+                float y = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
+                    layer, x, y, paint);
+            }
+            break;
+            case DrawBitmap: {
+                SkBitmap* bitmap = getBitmap();
+                float x = getFloat();
+                float y = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
+                    bitmap, x, y, paint);
+            }
+            break;
+            case DrawBitmapMatrix: {
+                SkBitmap* bitmap = getBitmap();
+                SkMatrix* matrix = getMatrix();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %p, %p, %p", (char*) indent, OP_NAMES[op],
+                    bitmap, matrix, paint);
+            }
+            break;
+            case DrawBitmapRect: {
+                SkBitmap* bitmap = getBitmap();
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                float f5 = getFloat();
+                float f6 = getFloat();
+                float f7 = getFloat();
+                float f8 = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
+                    (char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
+            }
+            break;
+            case DrawBitmapMesh: {
+                int verticesCount = 0;
+                uint32_t colorsCount = 0;
+                SkBitmap* bitmap = getBitmap();
+                uint32_t meshWidth = getInt();
+                uint32_t meshHeight = getInt();
+                float* vertices = getFloats(verticesCount);
+                bool hasColors = getInt();
+                int* colors = hasColors ? getInts(colorsCount) : NULL;
+                SkPaint* paint = getPaint();
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case DrawPatch: {
+                int32_t* xDivs = NULL;
+                int32_t* yDivs = NULL;
+                uint32_t* colors = NULL;
+                uint32_t xDivsCount = 0;
+                uint32_t yDivsCount = 0;
+                int8_t numColors = 0;
+                SkBitmap* bitmap = getBitmap();
+                xDivs = getInts(xDivsCount);
+                yDivs = getInts(yDivsCount);
+                colors = getUInts(numColors);
+                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+                getFloat();
+                getFloat();
+                getFloat();
+                getFloat();
+                getPaint();
+            }
+            break;
+            case DrawColor: {
+                int color = getInt();
+                int xferMode = getInt();
+                LOGD("%s%s 0x%x %d", (char*) indent, OP_NAMES[op], color, xferMode);
+            }
+            break;
+            case DrawRect: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
+                    f1, f2, f3, f4, paint);
+            }
+            break;
+            case DrawRoundRect: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                float f5 = getFloat();
+                float f6 = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
+                    (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint);
+            }
+            break;
+            case DrawCircle: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %.2f, %.2f, %.2f, %p",
+                    (char*) indent, OP_NAMES[op], f1, f2, f3, paint);
+            }
+            break;
+            case DrawOval: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p",
+                    (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint);
+            }
+            break;
+            case DrawArc: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                float f5 = getFloat();
+                float f6 = getFloat();
+                int i1 = getInt();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p",
+                    (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
+            }
+            break;
+            case DrawPath: {
+                SkPath* path = getPath();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %p, %p", (char*) indent, OP_NAMES[op], path, paint);
+            }
+            break;
+            case DrawLines: {
+                int count = 0;
+                float* points = getFloats(count);
+                SkPaint* paint = getPaint();
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case DrawPoints: {
+                int count = 0;
+                float* points = getFloats(count);
+                SkPaint* paint = getPaint();
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case DrawText: {
+                getText(&text);
+                int count = getInt();
+                float x = getFloat();
+                float y = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %s, %d, %d, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
+                    text.text(), text.length(), count, x, y, paint);
+            }
+            break;
+            case ResetShader: {
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case SetupShader: {
+                SkiaShader* shader = getShader();
+                LOGD("%s%s %p", (char*) indent, OP_NAMES[op], shader);
+            }
+            break;
+            case ResetColorFilter: {
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case SetupColorFilter: {
+                SkiaColorFilter *colorFilter = getColorFilter();
+                LOGD("%s%s %p", (char*) indent, OP_NAMES[op], colorFilter);
+            }
+            break;
+            case ResetShadow: {
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case SetupShadow: {
+                float radius = getFloat();
+                float dx = getFloat();
+                float dy = getFloat();
+                int color = getInt();
+                LOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op],
+                    radius, dx, dy, color);
+            }
+            break;
+            default:
+                LOGD("Display List error: op not handled: %s%s",
+                    (char*) indent, OP_NAMES[op]);
+                break;
+        }
+    }
+
+    LOGD("%sDone", (char*) indent + 2);
+}
+
+/**
+ * Changes to replay(), specifically those involving opcode or parameter changes, should be mimicked
+ * in the output() function, since that function processes the same list of opcodes for the
+ * purposes of logging display list info for a given view.
+ */
 bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) {
     bool needsInvalidate = false;
     TextContainer text;
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index b782103..dcf2cf2 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -107,6 +107,8 @@
 
     bool replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level = 0);
 
+    void output(OpenGLRenderer& renderer, uint32_t level = 0);
+
     static void outputLogBuffer(int fd);
 
 private:
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 16566b8..0310bc3 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -47,6 +47,7 @@
         meshElementCount = 0;
         isCacheable = true;
         isTextureLayer = false;
+        renderTarget = GL_TEXTURE_2D;
     }
 
     ~Layer() {
@@ -155,6 +156,11 @@
      * Optional texture coordinates transform.
      */
     mat4 texTransform;
+
+    /**
+     * Indicates the render target.
+     */
+    GLenum renderTarget;
 }; // struct Layer
 
 }; // namespace uirenderer
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index e167336..f316ba7 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -185,17 +185,7 @@
     layer->region.clear();
 
     glActiveTexture(GL_TEXTURE0);
-
     glGenTextures(1, &layer->texture);
-    glBindTexture(GL_TEXTURE_EXTERNAL_OES, layer->texture);
-
-    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
-
-    glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
-    glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
     return layer;
 }
@@ -280,7 +270,7 @@
 }
 
 void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
-        float* transform) {
+        GLenum renderTarget, float* transform) {
     if (layer) {
         layer->width = width;
         layer->height = height;
@@ -288,6 +278,15 @@
         layer->region.set(width, height);
         layer->regionRect.set(0.0f, 0.0f, width, height);
         layer->texTransform.load(transform);
+        layer->renderTarget = renderTarget;
+
+        glBindTexture(layer->renderTarget, layer->texture);
+
+        glTexParameteri(layer->renderTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glTexParameteri(layer->renderTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+        glTexParameteri(layer->renderTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameteri(layer->renderTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     }
 }
 
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index b3cd5db..59cab96 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -57,7 +57,7 @@
     static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false);
     static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
     static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
-            float* transform);
+            GLenum renderTarget, float* transform);
     static void destroyLayer(Layer* layer);
     static void destroyLayerDeferred(Layer* layer);
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 34d8fd3..f6a21d4 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -637,7 +637,12 @@
     float alpha = layer->alpha / 255.0f;
 
     setupDraw();
-    setupDrawWithExternalTexture();
+    if (layer->renderTarget == GL_TEXTURE_2D) {
+        setupDrawWithTexture();
+    } else {
+        setupDrawWithExternalTexture();
+    }
+    setupDrawTextureTransform();
     setupDrawColor(alpha, alpha, alpha, alpha);
     setupDrawColorFilter();
     setupDrawBlending(layer->blend, layer->mode);
@@ -645,8 +650,12 @@
     setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom);
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms();
-    setupDrawExternalTexture(layer->texture);
-    setupDrawTextureTransform(layer->texTransform);
+    if (layer->renderTarget == GL_TEXTURE_2D) {
+        setupDrawTexture(layer->texture);
+    } else {
+        setupDrawExternalTexture(layer->texture);
+    }
+    setupDrawTextureTransformUniforms(layer->texTransform);
     setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]);
 
     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
@@ -915,7 +924,7 @@
 }
 
 void OpenGLRenderer::setupDrawAALine() {
-    mDescription.hasWidth = true;
+    mDescription.isAA = true;
 }
 
 void OpenGLRenderer::setupDrawPoint(float pointSize) {
@@ -1095,7 +1104,11 @@
     glEnableVertexAttribArray(mTexCoordsSlot);
 }
 
-void OpenGLRenderer::setupDrawTextureTransform(mat4& transform) {
+void OpenGLRenderer::setupDrawTextureTransform() {
+    mDescription.hasTextureTransform = true;
+}
+
+void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) {
     glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1,
             GL_FALSE, &transform.data[0]);
 }
@@ -1121,25 +1134,30 @@
 
 /**
  * Sets up the shader to draw an AA line. We draw AA lines with quads, where there is an
- * outer boundary that fades out to 0. The variables set in the shader define the width of the
- * core line primitive ("width") and the width of the fading boundary ("boundaryWidth"). The
- * "vtxDistance" attribute (one per vertex) is a value from zero to one that tells the fragment
- * shader where the fragment is in relation to the line width overall; this value is then used
- * to compute the proper color, based on whether the fragment lies in the fading AA region of
- * the line.
+ * outer boundary that fades out to 0. The variables set in the shader define the proportion of
+ * the width and length of the primitive occupied by the AA region. The vtxWidth and vtxLength
+ * attributes (one per vertex) are values from zero to one that tells the fragment
+ * shader where the fragment is in relation to the line width/length overall; these values are
+ * then used to compute the proper color, based on whether the fragment lies in the fading AA
+ * region of the line.
+ * Note that we only pass down the width values in this setup function. The length coordinates
+ * are set up for each individual segment.
  */
-void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, float strokeWidth) {
+void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* widthCoords,
+        GLvoid* lengthCoords, float strokeWidth) {
     mCaches.unbindMeshBuffer();
     glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
-            gAlphaVertexStride, vertices);
-    int distanceSlot = mCaches.currentProgram->getAttrib("vtxDistance");
-    glEnableVertexAttribArray(distanceSlot);
-    glVertexAttribPointer(distanceSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, distanceCoords);
-    int widthSlot = mCaches.currentProgram->getUniform("width");
+            gAAVertexStride, vertices);
+    int widthSlot = mCaches.currentProgram->getAttrib("vtxWidth");
+    glEnableVertexAttribArray(widthSlot);
+    glVertexAttribPointer(widthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, widthCoords);
+    int lengthSlot = mCaches.currentProgram->getAttrib("vtxLength");
+    glEnableVertexAttribArray(lengthSlot);
+    glVertexAttribPointer(lengthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, lengthCoords);
     int boundaryWidthSlot = mCaches.currentProgram->getUniform("boundaryWidth");
+    // Setting the inverse value saves computations per-fragment in the shader
     int inverseBoundaryWidthSlot = mCaches.currentProgram->getUniform("inverseBoundaryWidth");
     float boundaryWidth = (1 - strokeWidth) / 2;
-    glUniform1f(widthSlot, strokeWidth);
     glUniform1f(boundaryWidthSlot, boundaryWidth);
     glUniform1f(inverseBoundaryWidthSlot, (1 / boundaryWidth));
 }
@@ -1167,6 +1185,12 @@
     return false;
 }
 
+void OpenGLRenderer::outputDisplayList(DisplayList* displayList, uint32_t level) {
+    if (displayList) {
+        displayList->output(*this, level);
+    }
+}
+
 void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint) {
     int alpha;
     SkXfermode::Mode mode;
@@ -1480,20 +1504,21 @@
     }
     Vertex lines[verticesCount];
     Vertex* vertices = &lines[0];
-    AlphaVertex wLines[verticesCount];
-    AlphaVertex* aaVertices = &wLines[0];
+    AAVertex wLines[verticesCount];
+    AAVertex* aaVertices = &wLines[0];
     if (!isAA) {
         setupDrawVertices(vertices);
     } else {
-        void* alphaCoords = ((GLbyte*) aaVertices) + gVertexAlphaOffset;
+        void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset;
+        void* lengthCoords = ((GLbyte*) aaVertices) + gVertexAALengthOffset;
         // innerProportion is the ratio of the inner (non-AA) port of the line to the total
         // AA stroke width (the base stroke width expanded by a half pixel on either side).
         // This value is used in the fragment shader to determine how to fill fragments.
         float innerProportion = fmax(strokeWidth - 1.0f, 0) / (strokeWidth + .5f);
-        setupDrawAALine((void*) aaVertices, alphaCoords, innerProportion);
+        setupDrawAALine((void*) aaVertices, widthCoords, lengthCoords, innerProportion);
     }
 
-    AlphaVertex *prevAAVertex = NULL;
+    AAVertex *prevAAVertex = NULL;
     Vertex *prevVertex = NULL;
     float inverseScaleX = 1.0f;
     float inverseScaleY = 1.0f;
@@ -1516,15 +1541,17 @@
         }
     }
 
+    int boundaryLengthSlot = -1;
+    int inverseBoundaryLengthSlot = -1;
     for (int i = 0; i < count; i += 4) {
         // a = start point, b = end point
         vec2 a(points[i], points[i + 1]);
         vec2 b(points[i + 2], points[i + 3]);
+        float length = 0;
 
         // Find the normal to the line
         vec2 n = (b - a).copyNormalized() * strokeWidth;
         if (isHairLine) {
-            n *= inverseScaleX;
             if (isAA) {
                 float wideningFactor;
                 if (fabs(n.x) >= fabs(n.y)) {
@@ -1534,27 +1561,35 @@
                 }
                 n *= wideningFactor;
             }
+            n.x *= inverseScaleX;
+            n.y *= inverseScaleY;
         }
         float x = n.x;
         n.x = -n.y;
         n.y = x;
 
+        // aa lines expand the endpoint vertices to encompass the AA boundary
+        if (isAA) {
+            vec2 abVector = (b - a);
+            length = abVector.length();
+            abVector.normalize();
+            a -= abVector;
+            b += abVector;
+        }
+
         // Four corners of the rectangle defining a thick line
         vec2 p1 = a - n;
         vec2 p2 = a + n;
         vec2 p3 = b + n;
         vec2 p4 = b - n;
 
+
         const float left = fmin(p1.x, fmin(p2.x, fmin(p3.x, p4.x)));
         const float right = fmax(p1.x, fmax(p2.x, fmax(p3.x, p4.x)));
         const float top = fmin(p1.y, fmin(p2.y, fmin(p3.y, p4.y)));
         const float bottom = fmax(p1.y, fmax(p2.y, fmax(p3.y, p4.y)));
 
         if (!quickReject(left, top, right, bottom)) {
-            // Draw the line as 2 triangles, could be optimized
-            // by using only 4 vertices and the correct indices
-            // Also we should probably used non textured vertices
-            // when line AA is disabled to save on bandwidth
             if (!isAA) {
                 if (prevVertex != NULL) {
                     // Issue two repeat vertices to create degenerate triangles to bridge
@@ -1572,24 +1607,36 @@
                 prevVertex = vertices - 1;
                 generatedVerticesCount += 4;
             } else {
+                if (boundaryLengthSlot < 0) {
+                    boundaryLengthSlot = mCaches.currentProgram->getUniform("boundaryLength");
+                    inverseBoundaryLengthSlot =
+                            mCaches.currentProgram->getUniform("inverseBoundaryLength");
+                }
+                float innerProportion = (length) / (length + 2);
+                float boundaryLength = (1 - innerProportion) / 2;
+                glUniform1f(boundaryLengthSlot, boundaryLength);
+                glUniform1f(inverseBoundaryLengthSlot, (1 / boundaryLength));
+
                 if (prevAAVertex != NULL) {
                     // Issue two repeat vertices to create degenerate triangles to bridge
                     // between the previous line and the new one. This is necessary because
                     // we are creating a single triangle_strip which will contain
                     // potentially discontinuous line segments.
-                    AlphaVertex::set(aaVertices++,prevAAVertex->position[0],
-                            prevAAVertex->position[1], prevAAVertex->alpha);
-                    AlphaVertex::set(aaVertices++, p4.x, p4.y, 1);
+                    AAVertex::set(aaVertices++,prevAAVertex->position[0],
+                            prevAAVertex->position[1], prevAAVertex->width, prevAAVertex->length);
+                    AAVertex::set(aaVertices++, p4.x, p4.y, 1, 1);
                     generatedVerticesCount += 2;
                 }
-                AlphaVertex::set(aaVertices++, p4.x, p4.y, 1);
-                AlphaVertex::set(aaVertices++, p1.x, p1.y, 1);
-                AlphaVertex::set(aaVertices++, p3.x, p3.y, 0);
-                AlphaVertex::set(aaVertices++, p2.x, p2.y, 0);
+                AAVertex::set(aaVertices++, p4.x, p4.y, 1, 1);
+                AAVertex::set(aaVertices++, p1.x, p1.y, 1, 0);
+                AAVertex::set(aaVertices++, p3.x, p3.y, 0, 1);
+                AAVertex::set(aaVertices++, p2.x, p2.y, 0, 0);
                 prevAAVertex = aaVertices - 1;
                 generatedVerticesCount += 4;
             }
-            dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
+            dirtyLayer(a.x == b.x ? left - 1 : left, a.y == b.y ? top - 1 : top,
+                    a.x == b.x ? right: right, a.y == b.y ? bottom: bottom,
+                    *mSnapshot->transform);
         }
     }
     if (generatedVerticesCount > 0) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 0ffd70b..271e4b1 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -98,6 +98,7 @@
 
     virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
             Rect& dirty, uint32_t level = 0);
+    virtual void outputDisplayList(DisplayList* displayList, uint32_t level = 0);
     virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
@@ -465,10 +466,12 @@
     void setupDrawSimpleMesh();
     void setupDrawTexture(GLuint texture);
     void setupDrawExternalTexture(GLuint texture);
-    void setupDrawTextureTransform(mat4& transform);
+    void setupDrawTextureTransform();
+    void setupDrawTextureTransformUniforms(mat4& transform);
     void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0);
     void setupDrawVertices(GLvoid* vertices);
-    void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, float strokeWidth);
+    void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, GLvoid* lengthCoords,
+            float strokeWidth);
     void finishDrawTexture();
 
     void drawRegionRects(const Region& region);
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 62ac2ba..d419e3e 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -39,8 +39,9 @@
         "attribute vec4 position;\n";
 const char* gVS_Header_Attributes_TexCoords =
         "attribute vec2 texCoords;\n";
-const char* gVS_Header_Attributes_Distance =
-        "attribute float vtxDistance;\n";
+const char* gVS_Header_Attributes_AAParameters =
+        "attribute float vtxWidth;\n"
+        "attribute float vtxLength;\n";
 const char* gVS_Header_Uniforms_TextureTransform =
         "uniform mat4 mainTextureTransform;\n";
 const char* gVS_Header_Uniforms =
@@ -60,8 +61,9 @@
         "uniform mediump vec2 textureDimension;\n";
 const char* gVS_Header_Varyings_HasTexture =
         "varying vec2 outTexCoords;\n";
-const char* gVS_Header_Varyings_HasWidth =
-        "varying float distance;\n";
+const char* gVS_Header_Varyings_IsAA =
+        "varying float widthProportion;\n"
+        "varying float lengthProportion;\n";
 const char* gVS_Header_Varyings_HasBitmap =
         "varying vec2 outBitmapTexCoords;\n";
 const char* gVS_Header_Varyings_PointHasBitmap =
@@ -96,8 +98,9 @@
         "    gl_Position = transform * position;\n";
 const char* gVS_Main_PointSize =
         "    gl_PointSize = pointSize;\n";
-const char* gVS_Main_Width =
-        "    distance = vtxDistance;\n";
+const char* gVS_Main_AA =
+        "    widthProportion = vtxWidth;\n"
+        "    lengthProportion = vtxLength;\n";
 const char* gVS_Footer =
         "}\n\n";
 
@@ -113,10 +116,11 @@
         "precision mediump float;\n\n";
 const char* gFS_Uniforms_Color =
         "uniform vec4 color;\n";
-const char* gFS_Uniforms_Width =
-        "uniform float width;\n"
+const char* gFS_Uniforms_AA =
         "uniform float boundaryWidth;\n"
-        "uniform float inverseBoundaryWidth;\n";
+        "uniform float inverseBoundaryWidth;\n"
+        "uniform float boundaryLength;\n"
+        "uniform float inverseBoundaryLength;\n";
 const char* gFS_Header_Uniforms_PointHasBitmap =
         "uniform vec2 textureDimension;\n"
         "uniform float pointSize;\n";
@@ -189,11 +193,16 @@
         "    fragColor = color;\n";
 const char* gFS_Main_ModulateColor =
         "    fragColor *= color.a;\n";
-const char* gFS_Main_AccountForWidth =
-        "    if (distance < boundaryWidth) {\n"
-        "        fragColor *= (distance * inverseBoundaryWidth);\n"
-        "    } else if (distance > (1.0 - boundaryWidth)) {\n"
-        "        fragColor *= ((1.0 - distance) * inverseBoundaryWidth);\n"
+const char* gFS_Main_AccountForAA =
+        "    if (widthProportion < boundaryWidth) {\n"
+        "        fragColor *= (widthProportion * inverseBoundaryWidth);\n"
+        "    } else if (widthProportion > (1.0 - boundaryWidth)) {\n"
+        "        fragColor *= ((1.0 - widthProportion) * inverseBoundaryWidth);\n"
+        "    }\n"
+        "    if (lengthProportion < boundaryLength) {\n"
+        "        fragColor *= (lengthProportion * inverseBoundaryLength);\n"
+        "    } else if (lengthProportion > (1.0 - boundaryLength)) {\n"
+        "        fragColor *= ((1.0 - lengthProportion) * inverseBoundaryLength);\n"
         "    }\n";
 const char* gFS_Main_FetchTexture[2] = {
         // Don't modulate
@@ -380,12 +389,12 @@
     if (description.hasTexture || description.hasExternalTexture) {
         shader.append(gVS_Header_Attributes_TexCoords);
     }
-    if (description.hasWidth) {
-        shader.append(gVS_Header_Attributes_Distance);
+    if (description.isAA) {
+        shader.append(gVS_Header_Attributes_AAParameters);
     }
     // Uniforms
     shader.append(gVS_Header_Uniforms);
-    if (description.hasExternalTexture) {
+    if (description.hasTextureTransform) {
         shader.append(gVS_Header_Uniforms_TextureTransform);
     }
     if (description.hasGradient) {
@@ -401,8 +410,8 @@
     if (description.hasTexture || description.hasExternalTexture) {
         shader.append(gVS_Header_Varyings_HasTexture);
     }
-    if (description.hasWidth) {
-        shader.append(gVS_Header_Varyings_HasWidth);
+    if (description.isAA) {
+        shader.append(gVS_Header_Varyings_IsAA);
     }
     if (description.hasGradient) {
         shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
@@ -415,14 +424,13 @@
 
     // Begin the shader
     shader.append(gVS_Main); {
-        if (description.hasTexture) {
+        if (description.hasTextureTransform) {
+            shader.append(gVS_Main_OutTransformedTexCoords);
+        } else if (description.hasTexture || description.hasExternalTexture) {
             shader.append(gVS_Main_OutTexCoords);
         }
-        if (description.hasExternalTexture) {
-            shader.append(gVS_Main_OutTransformedTexCoords);
-        }
-        if (description.hasWidth) {
-            shader.append(gVS_Main_Width);
+        if (description.isAA) {
+            shader.append(gVS_Main_AA);
         }
         if (description.hasGradient) {
             shader.append(gVS_Main_OutGradient[description.gradientType]);
@@ -464,8 +472,8 @@
     if (description.hasTexture || description.hasExternalTexture) {
         shader.append(gVS_Header_Varyings_HasTexture);
     }
-    if (description.hasWidth) {
-        shader.append(gVS_Header_Varyings_HasWidth);
+    if (description.isAA) {
+        shader.append(gVS_Header_Varyings_IsAA);
     }
     if (description.hasGradient) {
         shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
@@ -487,12 +495,11 @@
     }
     if (description.hasTexture) {
         shader.append(gFS_Uniforms_TextureSampler);
-    }
-    if (description.hasExternalTexture) {
+    } else if (description.hasExternalTexture) {
         shader.append(gFS_Uniforms_ExternalTextureSampler);
     }
-    if (description.hasWidth) {
-        shader.append(gFS_Uniforms_Width);
+    if (description.isAA) {
+        shader.append(gFS_Uniforms_AA);
     }
     if (description.hasGradient) {
         shader.append(gFS_Uniforms_GradientSampler[description.gradientType]);
@@ -502,7 +509,7 @@
     }
 
     // Optimization for common cases
-    if (!description.hasWidth && !blendFramebuffer &&
+    if (!description.isAA && !blendFramebuffer &&
             description.colorOp == ProgramDescription::kColorNone && !description.isPoint) {
         bool fast = false;
 
@@ -587,8 +594,8 @@
                 shader.append(gFS_Main_FetchColor);
             }
         }
-        if (description.hasWidth) {
-            shader.append(gFS_Main_AccountForWidth);
+        if (description.isAA) {
+            shader.append(gFS_Main_AccountForAA);
         }
         if (description.hasGradient) {
             shader.append(gFS_Main_FetchGradient[description.gradientType]);
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index 70909fd..5c7197b 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -75,9 +75,10 @@
 
 #define PROGRAM_IS_POINT_SHIFT 36
 
-#define PROGRAM_HAS_WIDTH_SHIFT 37
+#define PROGRAM_HAS_AA_SHIFT 37
 
 #define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38
+#define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39
 
 ///////////////////////////////////////////////////////////////////////////////
 // Types
@@ -116,6 +117,7 @@
     bool hasTexture;
     bool hasAlpha8Texture;
     bool hasExternalTexture;
+    bool hasTextureTransform;
 
     // Modulate, this should only be set when setColor() return true
     bool modulate;
@@ -124,7 +126,7 @@
     bool hasBitmap;
     bool isBitmapNpot;
 
-    bool hasWidth;
+    bool isAA;
 
     bool hasGradient;
     Gradient gradientType;
@@ -155,8 +157,9 @@
         hasTexture = false;
         hasAlpha8Texture = false;
         hasExternalTexture = false;
+        hasTextureTransform = false;
 
-        hasWidth = false;
+        isAA = false;
 
         modulate = false;
 
@@ -243,8 +246,9 @@
         if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST;
         if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT;
         if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT;
-        if (hasWidth) key |= programid(0x1) << PROGRAM_HAS_WIDTH_SHIFT;
+        if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT;
         if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT;
+        if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT;
         return key;
     }
 
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index c120428..38455dc 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -68,6 +68,25 @@
     }
 }; // struct AlphaVertex
 
+/**
+ * Simple structure to describe a vertex with a position and an alpha value.
+ */
+struct AAVertex : Vertex {
+    float width;
+    float length;
+
+    static inline void set(AAVertex* vertex, float x, float y, float width, float length) {
+        Vertex::set(vertex, x, y);
+        vertex[0].width = width;
+        vertex[0].length = length;
+    }
+
+    static inline void setColor(AAVertex* vertex, float width, float length) {
+        vertex[0].width = width;
+        vertex[0].length = length;
+    }
+}; // struct AlphaVertex
+
 }; // namespace uirenderer
 }; // namespace android
 
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
index a99a599..c336c0d 100644
--- a/libs/rs/Android.mk
+++ b/libs/rs/Android.mk
@@ -110,20 +110,24 @@
 	rsScriptC.cpp \
 	rsScriptC_Lib.cpp \
 	rsScriptC_LibGL.cpp \
-	rsShaderCache.cpp \
 	rsSignal.cpp \
 	rsStream.cpp \
 	rsThreadIO.cpp \
 	rsType.cpp \
-	rsVertexArray.cpp \
 	driver/rsdBcc.cpp \
 	driver/rsdCore.cpp \
 	driver/rsdGL.cpp \
+	driver/rsdMesh.cpp \
+	driver/rsdMeshObj.cpp \
+	driver/rsdProgram.cpp \
 	driver/rsdProgramRaster.cpp \
 	driver/rsdProgramStore.cpp \
 	driver/rsdRuntimeMath.cpp \
-	driver/rsdRuntimeStubs.cpp
-
+	driver/rsdRuntimeStubs.cpp \
+	driver/rsdSampler.cpp \
+	driver/rsdShader.cpp \
+	driver/rsdShaderCache.cpp \
+	driver/rsdVertexArray.cpp
 
 LOCAL_SHARED_LIBRARIES += libz libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libbcc
 
diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp
index 5b80439..0a5f2ec 100644
--- a/libs/rs/driver/rsdCore.cpp
+++ b/libs/rs/driver/rsdCore.cpp
@@ -19,6 +19,10 @@
 #include "rsdGL.h"
 #include "rsdProgramStore.h"
 #include "rsdProgramRaster.h"
+#include "rsdProgramVertex.h"
+#include "rsdProgramFragment.h"
+#include "rsdMesh.h"
+#include "rsdSampler.h"
 
 #include <malloc.h>
 #include "rsContext.h"
@@ -69,7 +73,30 @@
         rsdProgramRasterInit,
         rsdProgramRasterSetActive,
         rsdProgramRasterDestroy
-    }
+    },
+
+    {
+        rsdProgramVertexInit,
+        rsdProgramVertexSetActive,
+        rsdProgramVertexDestroy
+    },
+
+    {
+        rsdProgramFragmentInit,
+        rsdProgramFragmentSetActive,
+        rsdProgramFragmentDestroy
+    },
+
+    {
+        rsdMeshInit,
+        rsdMeshDraw,
+        rsdMeshDestroy
+    },
+
+    {
+        rsdSamplerInit,
+        rsdSamplerDestroy
+    },
 
 };
 
diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp
index 26e1bdf..48690d5 100644
--- a/libs/rs/driver/rsdGL.cpp
+++ b/libs/rs/driver/rsdGL.cpp
@@ -40,6 +40,8 @@
 
 #include <malloc.h>
 #include "rsContext.h"
+#include "rsdShaderCache.h"
+#include "rsdVertexArray.h"
 
 using namespace android;
 using namespace android::renderscript;
@@ -128,6 +130,11 @@
 void rsdGLShutdown(const Context *rsc) {
     RsdHal *dc = (RsdHal *)rsc->mHal.drv;
 
+    dc->gl.shaderCache->cleanupAll();
+    delete dc->gl.shaderCache;
+
+    delete dc->gl.vertexArrayState;
+
     LOGV("%p, deinitEGL", rsc);
 
     if (dc->gl.egl.context != EGL_NO_CONTEXT) {
@@ -287,6 +294,10 @@
         DumpDebug(dc);
     }
 
+    dc->gl.shaderCache = new RsdShaderCache();
+    dc->gl.vertexArrayState = new RsdVertexArrayState();
+    dc->gl.vertexArrayState->init(dc->gl.gl.maxVertexAttribs);
+
     LOGV("initGLThread end %p", rsc);
     return true;
 }
diff --git a/libs/rs/driver/rsdGL.h b/libs/rs/driver/rsdGL.h
index 246931f..351b2d5 100644
--- a/libs/rs/driver/rsdGL.h
+++ b/libs/rs/driver/rsdGL.h
@@ -19,7 +19,8 @@
 
 #include <rs_hal.h>
 
-
+class RsdShaderCache;
+class RsdVertexArrayState;
 
 typedef void (* InvokeFunc_t)(void);
 typedef void (*WorkerCallback_t)(void *usr, uint32_t idx);
@@ -64,6 +65,8 @@
     ANativeWindow *wndSurface;
     uint32_t width;
     uint32_t height;
+    RsdShaderCache *shaderCache;
+    RsdVertexArrayState *vertexArrayState;
 } RsdGL;
 
 
diff --git a/libs/rs/driver/rsdMesh.cpp b/libs/rs/driver/rsdMesh.cpp
new file mode 100644
index 0000000..eb62ddb
--- /dev/null
+++ b/libs/rs/driver/rsdMesh.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2011 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 <rs_hal.h>
+#include <rsContext.h>
+#include <rsMesh.h>
+
+#include "rsdCore.h"
+#include "rsdMesh.h"
+#include "rsdMeshObj.h"
+#include "rsdShaderCache.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+bool rsdMeshInit(const Context *rsc, const Mesh *m) {
+    RsdMeshObj *drv = NULL;
+    if(m->mHal.drv) {
+        drv = (RsdMeshObj*)m->mHal.drv;
+        delete drv;
+    }
+    drv = new RsdMeshObj(rsc, m);
+    m->mHal.drv = drv;
+    return drv->init();
+}
+
+void rsdMeshDraw(const Context *rsc, const Mesh *m, uint32_t primIndex, uint32_t start, uint32_t len) {
+    if(m->mHal.drv) {
+        RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+        if (!dc->gl.shaderCache->setup(rsc)) {
+            return;
+        }
+
+        RsdMeshObj *drv = (RsdMeshObj*)m->mHal.drv;
+        drv->renderPrimitiveRange(rsc, primIndex, start, len);
+    }
+}
+
+void rsdMeshDestroy(const Context *rsc, const Mesh *m) {
+    if(m->mHal.drv) {
+        RsdMeshObj *drv = (RsdMeshObj*)m->mHal.drv;
+        delete drv;
+    }
+}
+
+
diff --git a/libs/rs/driver/rsdMesh.h b/libs/rs/driver/rsdMesh.h
new file mode 100644
index 0000000..d2714fd
--- /dev/null
+++ b/libs/rs/driver/rsdMesh.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2011 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 RSD_MESH_H
+#define RSD_MESH_H
+
+#include <rs_hal.h>
+
+
+bool rsdMeshInit(const android::renderscript::Context *rsc,
+                 const android::renderscript::Mesh *m);
+void rsdMeshDraw(const android::renderscript::Context *rsc,
+                 const android::renderscript::Mesh *m,
+                 uint32_t primIndex, uint32_t start, uint32_t len);
+void rsdMeshDestroy(const android::renderscript::Context *rsc,
+                    const android::renderscript::Mesh *m);
+
+
+#endif
diff --git a/libs/rs/driver/rsdMeshObj.cpp b/libs/rs/driver/rsdMeshObj.cpp
new file mode 100644
index 0000000..6bb33f7
--- /dev/null
+++ b/libs/rs/driver/rsdMeshObj.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2011 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 <GLES/gl.h>
+#include <GLES2/gl2.h>
+#include <GLES/glext.h>
+
+#include <rs_hal.h>
+#include <rsContext.h>
+#include <rsMesh.h>
+
+#include "rsdMeshObj.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+RsdMeshObj::RsdMeshObj(const Context *rsc, const Mesh *rsMesh) {
+    mRSMesh = rsMesh;
+
+    mAttribs = NULL;
+    mAttribAllocationIndex = NULL;
+    mGLPrimitives = NULL;
+
+    mAttribCount = 0;
+}
+
+RsdMeshObj::~RsdMeshObj() {
+    if (mAttribs) {
+        delete[] mAttribs;
+        delete[] mAttribAllocationIndex;
+    }
+    if (mGLPrimitives) {
+        delete[] mGLPrimitives;
+    }
+}
+
+bool RsdMeshObj::isValidGLComponent(const Element *elem, uint32_t fieldIdx) {
+    // Do not create attribs for padding
+    if (elem->getFieldName(fieldIdx)[0] == '#') {
+        return false;
+    }
+
+    // Only GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, GL_FLOAT are accepted.
+    // Filter rs types accordingly
+    RsDataType dt = elem->getField(fieldIdx)->getComponent().getType();
+    if (dt != RS_TYPE_FLOAT_32 && dt != RS_TYPE_UNSIGNED_8 &&
+        dt != RS_TYPE_UNSIGNED_16 && dt != RS_TYPE_SIGNED_8 &&
+        dt != RS_TYPE_SIGNED_16) {
+        return false;
+    }
+
+    // Now make sure they are not arrays
+    uint32_t arraySize = elem->getFieldArraySize(fieldIdx);
+    if (arraySize != 1) {
+        return false;
+    }
+
+    return true;
+}
+
+bool RsdMeshObj::init() {
+
+    updateGLPrimitives();
+
+    // Count the number of gl attrs to initialize
+    mAttribCount = 0;
+    for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) {
+        const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement();
+        for (uint32_t ct=0; ct < elem->getFieldCount(); ct++) {
+            if (isValidGLComponent(elem, ct)) {
+                mAttribCount ++;
+            }
+        }
+    }
+
+    if (mAttribs) {
+        delete [] mAttribs;
+        delete [] mAttribAllocationIndex;
+        mAttribs = NULL;
+        mAttribAllocationIndex = NULL;
+    }
+    if (!mAttribCount) {
+        return false;
+    }
+
+    mAttribs = new RsdVertexArray::Attrib[mAttribCount];
+    mAttribAllocationIndex = new uint32_t[mAttribCount];
+
+    uint32_t userNum = 0;
+    for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) {
+        const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement();
+        uint32_t stride = elem->getSizeBytes();
+        for (uint32_t fieldI=0; fieldI < elem->getFieldCount(); fieldI++) {
+            const Component &c = elem->getField(fieldI)->getComponent();
+
+            if (!isValidGLComponent(elem, fieldI)) {
+                continue;
+            }
+
+            mAttribs[userNum].size = c.getVectorSize();
+            mAttribs[userNum].offset = elem->getFieldOffsetBytes(fieldI);
+            mAttribs[userNum].type = c.getGLType();
+            mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized();
+            mAttribs[userNum].stride = stride;
+            String8 tmp(RS_SHADER_ATTR);
+            tmp.append(elem->getFieldName(fieldI));
+            mAttribs[userNum].name.setTo(tmp.string());
+
+            // Remember which allocation this attribute came from
+            mAttribAllocationIndex[userNum] = ct;
+            userNum ++;
+        }
+    }
+
+    return true;
+}
+
+void RsdMeshObj::renderPrimitiveRange(const Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const {
+    if (len < 1 || primIndex >= mRSMesh->mHal.state.primitivesCount || mAttribCount == 0) {
+        LOGE("Invalid mesh or parameters");
+        return;
+    }
+
+    rsc->checkError("Mesh::renderPrimitiveRange 1");
+    // update attributes with either buffer information or data ptr based on their current state
+    for (uint32_t ct=0; ct < mAttribCount; ct++) {
+        uint32_t allocIndex = mAttribAllocationIndex[ct];
+        Allocation *alloc = mRSMesh->mHal.state.vertexBuffers[allocIndex].get();
+        if (alloc->getIsBufferObject() && alloc->getBufferObjectID()) {
+            mAttribs[ct].buffer = alloc->getBufferObjectID();
+            mAttribs[ct].ptr = NULL;
+        } else {
+            mAttribs[ct].buffer = 0;
+            mAttribs[ct].ptr = (const uint8_t*)alloc->getPtr();
+        }
+    }
+
+    RsdVertexArray va(mAttribs, mAttribCount);
+    va.setupGL2(rsc);
+
+    rsc->checkError("Mesh::renderPrimitiveRange 2");
+    Mesh::Primitive_t *prim = mRSMesh->mHal.state.primitives[primIndex];
+    if (prim->mIndexBuffer.get()) {
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prim->mIndexBuffer->getBufferObjectID());
+        glDrawElements(mGLPrimitives[primIndex], len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2));
+    } else {
+        glDrawArrays(mGLPrimitives[primIndex], start, len);
+    }
+
+    rsc->checkError("Mesh::renderPrimitiveRange");
+}
+
+void RsdMeshObj::updateGLPrimitives() {
+    mGLPrimitives = new uint32_t[mRSMesh->mHal.state.primitivesCount];
+    for (uint32_t i = 0; i < mRSMesh->mHal.state.primitivesCount; i ++) {
+        switch (mRSMesh->mHal.state.primitives[i]->mPrimitive) {
+            case RS_PRIMITIVE_POINT:          mGLPrimitives[i] = GL_POINTS; break;
+            case RS_PRIMITIVE_LINE:           mGLPrimitives[i] = GL_LINES; break;
+            case RS_PRIMITIVE_LINE_STRIP:     mGLPrimitives[i] = GL_LINE_STRIP; break;
+            case RS_PRIMITIVE_TRIANGLE:       mGLPrimitives[i] = GL_TRIANGLES; break;
+            case RS_PRIMITIVE_TRIANGLE_STRIP: mGLPrimitives[i] = GL_TRIANGLE_STRIP; break;
+            case RS_PRIMITIVE_TRIANGLE_FAN:   mGLPrimitives[i] = GL_TRIANGLE_FAN; break;
+        }
+    }
+}
diff --git a/libs/rs/driver/rsdMeshObj.h b/libs/rs/driver/rsdMeshObj.h
new file mode 100644
index 0000000..8b1271b
--- /dev/null
+++ b/libs/rs/driver/rsdMeshObj.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 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_RSD_MESH_OBJ_H
+#define ANDROID_RSD_MESH_OBJ_H
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+    class Context;
+    class Mesh;
+    class Element;
+
+}
+}
+
+#include "driver/rsdVertexArray.h"
+
+// An element is a group of Components that occupies one cell in a structure.
+class RsdMeshObj {
+public:
+    RsdMeshObj(const android::renderscript::Context *,
+            const android::renderscript::Mesh *);
+    ~RsdMeshObj();
+
+    void renderPrimitiveRange(const android::renderscript::Context *, uint32_t primIndex, uint32_t start, uint32_t len) const;
+
+    bool init();
+
+protected:
+    const android::renderscript::Mesh *mRSMesh;
+
+    uint32_t *mGLPrimitives;
+    void updateGLPrimitives();
+
+    bool isValidGLComponent(const android::renderscript::Element *elem, uint32_t fieldIdx);
+    // Attribues that allow us to map to GL
+    RsdVertexArray::Attrib *mAttribs;
+    // This allows us to figure out which allocation the attribute
+    // belongs to. In the event the allocation is uploaded to GL
+    // buffer, it lets us properly map it
+    uint32_t *mAttribAllocationIndex;
+    uint32_t mAttribCount;
+};
+
+#endif //ANDROID_RSD_MESH_OBJ_H
+
+
+
diff --git a/libs/rs/driver/rsdProgram.cpp b/libs/rs/driver/rsdProgram.cpp
new file mode 100644
index 0000000..502c5ee
--- /dev/null
+++ b/libs/rs/driver/rsdProgram.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2011 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 "rsdCore.h"
+#include "rsdProgramVertex.h"
+#include "rsdShader.h"
+#include "rsdShaderCache.h"
+
+#include "rsContext.h"
+#include "rsProgramVertex.h"
+#include "rsProgramFragment.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+bool rsdProgramVertexInit(const Context *rsc, const ProgramVertex *pv,
+                          const char* shader, uint32_t shaderLen) {
+    RsdShader *drv = new RsdShader(pv, GL_VERTEX_SHADER, shader, shaderLen);
+    pv->mHal.drv = drv;
+
+    return drv->createShader();
+}
+
+void rsdProgramVertexSetActive(const Context *rsc, const ProgramVertex *pv) {
+    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+
+    dc->gl.shaderCache->setActiveVertex((RsdShader*)pv->mHal.drv);
+}
+
+void rsdProgramVertexDestroy(const Context *rsc, const ProgramVertex *pv) {
+    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+
+    RsdShader *drv = NULL;
+    if(pv->mHal.drv) {
+        drv = (RsdShader*)pv->mHal.drv;
+        if (rsc->props.mLogShaders) {
+            LOGV("Destroying vertex shader with ID %u", drv->getShaderID());
+        }
+        if (drv->getShaderID()) {
+            dc->gl.shaderCache->cleanupVertex(drv->getShaderID());
+        }
+        delete drv;
+    }
+}
+
+bool rsdProgramFragmentInit(const Context *rsc, const ProgramFragment *pf,
+                          const char* shader, uint32_t shaderLen) {
+    RsdShader *drv = new RsdShader(pf, GL_FRAGMENT_SHADER, shader, shaderLen);
+    pf->mHal.drv = drv;
+
+    return drv->createShader();
+}
+
+void rsdProgramFragmentSetActive(const Context *rsc, const ProgramFragment *pf) {
+    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+
+    dc->gl.shaderCache->setActiveFragment((RsdShader*)pf->mHal.drv);
+}
+
+void rsdProgramFragmentDestroy(const Context *rsc, const ProgramFragment *pf) {
+    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+
+    RsdShader *drv = NULL;
+    if(pf->mHal.drv) {
+        drv = (RsdShader*)pf->mHal.drv;
+        if (rsc->props.mLogShaders) {
+            LOGV("Destroying fragment shader with ID %u", drv->getShaderID());
+        }
+        if (drv->getShaderID()) {
+            dc->gl.shaderCache->cleanupFragment(drv->getShaderID());
+        }
+        delete drv;
+    }
+}
+
+
diff --git a/libs/rs/driver/rsdProgramFragment.h b/libs/rs/driver/rsdProgramFragment.h
new file mode 100644
index 0000000..366cb40
--- /dev/null
+++ b/libs/rs/driver/rsdProgramFragment.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2011 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 RSD_PROGRAM_FRAGMENT_H
+#define RSD_PROGRAM_FRAGMENT_H
+
+#include <rs_hal.h>
+
+
+bool rsdProgramFragmentInit(const android::renderscript::Context *rsc,
+                            const android::renderscript::ProgramFragment *,
+                            const char* shader, uint32_t shaderLen);
+void rsdProgramFragmentSetActive(const android::renderscript::Context *rsc,
+                                 const android::renderscript::ProgramFragment *);
+void rsdProgramFragmentDestroy(const android::renderscript::Context *rsc,
+                               const android::renderscript::ProgramFragment *);
+
+
+#endif //RSD_PROGRAM_Fragment_H
diff --git a/libs/rs/driver/rsdProgramVertex.h b/libs/rs/driver/rsdProgramVertex.h
new file mode 100644
index 0000000..e998572
--- /dev/null
+++ b/libs/rs/driver/rsdProgramVertex.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 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 RSD_PROGRAM_VERTEX_H
+#define RSD_PROGRAM_VERTEX_H
+
+#include <rs_hal.h>
+
+bool rsdProgramVertexInit(const android::renderscript::Context *rsc,
+                          const android::renderscript::ProgramVertex *,
+                          const char* shader, uint32_t shaderLen);
+void rsdProgramVertexSetActive(const android::renderscript::Context *rsc,
+                               const android::renderscript::ProgramVertex *);
+void rsdProgramVertexDestroy(const android::renderscript::Context *rsc,
+                             const android::renderscript::ProgramVertex *);
+
+
+#endif //RSD_PROGRAM_VERTEX_H
diff --git a/libs/rs/driver/rsdRuntimeMath.cpp b/libs/rs/driver/rsdRuntimeMath.cpp
index 093e311..acb990d 100644
--- a/libs/rs/driver/rsdRuntimeMath.cpp
+++ b/libs/rs/driver/rsdRuntimeMath.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
diff --git a/libs/rs/driver/rsdRuntimeStubs.cpp b/libs/rs/driver/rsdRuntimeStubs.cpp
index b70a123..9cbff95 100644
--- a/libs/rs/driver/rsdRuntimeStubs.cpp
+++ b/libs/rs/driver/rsdRuntimeStubs.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
diff --git a/libs/rs/driver/rsdSampler.cpp b/libs/rs/driver/rsdSampler.cpp
new file mode 100644
index 0000000..af48c61
--- /dev/null
+++ b/libs/rs/driver/rsdSampler.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2011 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 "rsdCore.h"
+#include "rsdSampler.h"
+
+#include "rsContext.h"
+#include "rsSampler.h"
+#include "rsProgramVertex.h"
+#include "rsProgramFragment.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+
+using namespace android;
+using namespace android::renderscript;
+
+bool rsdSamplerInit(const android::renderscript::Context *,
+                    const android::renderscript::Sampler *) {
+    return true;
+}
+
+void rsdSamplerDestroy(const android::renderscript::Context *rsc,
+                       const android::renderscript::Sampler *s) {
+}
diff --git a/libs/rs/driver/rsdSampler.h b/libs/rs/driver/rsdSampler.h
new file mode 100644
index 0000000..3a64e9e
--- /dev/null
+++ b/libs/rs/driver/rsdSampler.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 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 RSD_SAMPLER_H
+#define RSD_SAMPLER_H
+
+#include <rs_hal.h>
+
+
+bool rsdSamplerInit(const android::renderscript::Context *rsc,
+                    const android::renderscript::Sampler *);
+
+void rsdSamplerDestroy(const android::renderscript::Context *rsc,
+                       const android::renderscript::Sampler *);
+
+
+#endif // RSD_SAMPLER_H
diff --git a/libs/rs/driver/rsdShader.cpp b/libs/rs/driver/rsdShader.cpp
new file mode 100644
index 0000000..1710a8b
--- /dev/null
+++ b/libs/rs/driver/rsdShader.cpp
@@ -0,0 +1,533 @@
+/*
+ * Copyright (C) 2011 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 <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <rs_hal.h>
+#include <rsContext.h>
+#include <rsProgram.h>
+
+#include "rsdCore.h"
+#include "rsdShader.h"
+#include "rsdShaderCache.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+RsdShader::RsdShader(const Program *p, uint32_t type,
+                       const char * shaderText, uint32_t shaderLength) {
+
+    mUserShader.setTo(shaderText, shaderLength);
+    mRSProgram = p;
+    mType = type;
+    initMemberVars();
+    initAttribAndUniformArray();
+    init();
+}
+
+RsdShader::~RsdShader() {
+    if (mShaderID) {
+        glDeleteShader(mShaderID);
+    }
+
+    delete[] mAttribNames;
+    delete[] mUniformNames;
+    delete[] mUniformArraySizes;
+}
+
+void RsdShader::initMemberVars() {
+    mDirty = true;
+    mShaderID = 0;
+    mAttribCount = 0;
+    mUniformCount = 0;
+
+    mAttribNames = NULL;
+    mUniformNames = NULL;
+    mUniformArraySizes = NULL;
+
+    mIsValid = false;
+}
+
+void RsdShader::init() {
+    uint32_t attribCount = 0;
+    uint32_t uniformCount = 0;
+    for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
+        initAddUserElement(mRSProgram->mHal.state.inputElements[ct].get(), mAttribNames, NULL, &attribCount, RS_SHADER_ATTR);
+    }
+    for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
+        initAddUserElement(mRSProgram->mHal.state.constantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI);
+    }
+
+    mTextureUniformIndexStart = uniformCount;
+    char buf[256];
+    for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) {
+        snprintf(buf, sizeof(buf), "UNI_Tex%i", ct);
+        mUniformNames[uniformCount].setTo(buf);
+        mUniformArraySizes[uniformCount] = 1;
+        uniformCount++;
+    }
+}
+
+String8 RsdShader::getGLSLInputString() const {
+    String8 s;
+    for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
+        const Element *e = mRSProgram->mHal.state.inputElements[ct].get();
+        for (uint32_t field=0; field < e->getFieldCount(); field++) {
+            const Element *f = e->getField(field);
+
+            // Cannot be complex
+            rsAssert(!f->getFieldCount());
+            switch (f->getComponent().getVectorSize()) {
+            case 1: s.append("attribute float ATTRIB_"); break;
+            case 2: s.append("attribute vec2 ATTRIB_"); break;
+            case 3: s.append("attribute vec3 ATTRIB_"); break;
+            case 4: s.append("attribute vec4 ATTRIB_"); break;
+            default:
+                rsAssert(0);
+            }
+
+            s.append(e->getFieldName(field));
+            s.append(";\n");
+        }
+    }
+    return s;
+}
+
+void RsdShader::appendAttributes() {
+    for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
+        const Element *e = mRSProgram->mHal.state.inputElements[ct].get();
+        for (uint32_t field=0; field < e->getFieldCount(); field++) {
+            const Element *f = e->getField(field);
+            const char *fn = e->getFieldName(field);
+
+            if (fn[0] == '#') {
+                continue;
+            }
+
+            // Cannot be complex
+            rsAssert(!f->getFieldCount());
+            switch (f->getComponent().getVectorSize()) {
+            case 1: mShader.append("attribute float ATTRIB_"); break;
+            case 2: mShader.append("attribute vec2 ATTRIB_"); break;
+            case 3: mShader.append("attribute vec3 ATTRIB_"); break;
+            case 4: mShader.append("attribute vec4 ATTRIB_"); break;
+            default:
+                rsAssert(0);
+            }
+
+            mShader.append(fn);
+            mShader.append(";\n");
+        }
+    }
+}
+
+void RsdShader::appendTextures() {
+    char buf[256];
+    for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) {
+        if (mRSProgram->mHal.state.textureTargets[ct] == RS_TEXTURE_2D) {
+            snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct);
+        } else {
+            snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct);
+        }
+        mShader.append(buf);
+    }
+}
+
+bool RsdShader::createShader() {
+
+    if (mType == GL_FRAGMENT_SHADER) {
+        mShader.append("precision mediump float;\n");
+    }
+    appendUserConstants();
+    appendAttributes();
+    appendTextures();
+
+    mShader.append(mUserShader);
+
+    return true;
+}
+
+bool RsdShader::loadShader(const Context *rsc) {
+    mShaderID = glCreateShader(mType);
+    rsAssert(mShaderID);
+
+    if (rsc->props.mLogShaders) {
+        LOGV("Loading shader type %x, ID %i", mType, mShaderID);
+        LOGV("%s", mShader.string());
+    }
+
+    if (mShaderID) {
+        const char * ss = mShader.string();
+        glShaderSource(mShaderID, 1, &ss, NULL);
+        glCompileShader(mShaderID);
+
+        GLint compiled = 0;
+        glGetShaderiv(mShaderID, GL_COMPILE_STATUS, &compiled);
+        if (!compiled) {
+            GLint infoLen = 0;
+            glGetShaderiv(mShaderID, GL_INFO_LOG_LENGTH, &infoLen);
+            if (infoLen) {
+                char* buf = (char*) malloc(infoLen);
+                if (buf) {
+                    glGetShaderInfoLog(mShaderID, infoLen, NULL, buf);
+                    LOGE("Could not compile shader \n%s\n", buf);
+                    free(buf);
+                }
+                glDeleteShader(mShaderID);
+                mShaderID = 0;
+                rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,");
+                return false;
+            }
+        }
+    }
+
+    if (rsc->props.mLogShaders) {
+        LOGV("--Shader load result %x ", glGetError());
+    }
+    mIsValid = true;
+    return true;
+}
+
+void RsdShader::appendUserConstants() {
+    for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
+        const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement();
+        for (uint32_t field=0; field < e->getFieldCount(); field++) {
+            const Element *f = e->getField(field);
+            const char *fn = e->getFieldName(field);
+
+            if (fn[0] == '#') {
+                continue;
+            }
+
+            // Cannot be complex
+            rsAssert(!f->getFieldCount());
+            if (f->getType() == RS_TYPE_MATRIX_4X4) {
+                mShader.append("uniform mat4 UNI_");
+            } else if (f->getType() == RS_TYPE_MATRIX_3X3) {
+                mShader.append("uniform mat3 UNI_");
+            } else if (f->getType() == RS_TYPE_MATRIX_2X2) {
+                mShader.append("uniform mat2 UNI_");
+            } else {
+                switch (f->getComponent().getVectorSize()) {
+                case 1: mShader.append("uniform float UNI_"); break;
+                case 2: mShader.append("uniform vec2 UNI_"); break;
+                case 3: mShader.append("uniform vec3 UNI_"); break;
+                case 4: mShader.append("uniform vec4 UNI_"); break;
+                default:
+                    rsAssert(0);
+                }
+            }
+
+            mShader.append(fn);
+            if (e->getFieldArraySize(field) > 1) {
+                mShader.appendFormat("[%d]", e->getFieldArraySize(field));
+            }
+            mShader.append(";\n");
+        }
+    }
+}
+
+void RsdShader::logUniform(const Element *field, const float *fd, uint32_t arraySize ) {
+    RsDataType dataType = field->getType();
+    uint32_t elementSize = field->getSizeBytes() / sizeof(float);
+    for (uint32_t i = 0; i < arraySize; i ++) {
+        if (arraySize > 1) {
+            LOGV("Array Element [%u]", i);
+        }
+        if (dataType == RS_TYPE_MATRIX_4X4) {
+            LOGV("Matrix4x4");
+            LOGV("{%f, %f, %f, %f",  fd[0], fd[4], fd[8], fd[12]);
+            LOGV(" %f, %f, %f, %f",  fd[1], fd[5], fd[9], fd[13]);
+            LOGV(" %f, %f, %f, %f",  fd[2], fd[6], fd[10], fd[14]);
+            LOGV(" %f, %f, %f, %f}", fd[3], fd[7], fd[11], fd[15]);
+        } else if (dataType == RS_TYPE_MATRIX_3X3) {
+            LOGV("Matrix3x3");
+            LOGV("{%f, %f, %f",  fd[0], fd[3], fd[6]);
+            LOGV(" %f, %f, %f",  fd[1], fd[4], fd[7]);
+            LOGV(" %f, %f, %f}", fd[2], fd[5], fd[8]);
+        } else if (dataType == RS_TYPE_MATRIX_2X2) {
+            LOGV("Matrix2x2");
+            LOGV("{%f, %f",  fd[0], fd[2]);
+            LOGV(" %f, %f}", fd[1], fd[3]);
+        } else {
+            switch (field->getComponent().getVectorSize()) {
+            case 1:
+                LOGV("Uniform 1 = %f", fd[0]);
+                break;
+            case 2:
+                LOGV("Uniform 2 = %f %f", fd[0], fd[1]);
+                break;
+            case 3:
+                LOGV("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]);
+                break;
+            case 4:
+                LOGV("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]);
+                break;
+            default:
+                rsAssert(0);
+            }
+        }
+        LOGE("Element size %u data=%p", elementSize, fd);
+        fd += elementSize;
+        LOGE("New data=%p", fd);
+    }
+}
+
+void RsdShader::setUniform(const Context *rsc, const Element *field, const float *fd,
+                         int32_t slot, uint32_t arraySize ) {
+    RsDataType dataType = field->getType();
+    if (dataType == RS_TYPE_MATRIX_4X4) {
+        glUniformMatrix4fv(slot, arraySize, GL_FALSE, fd);
+    } else if (dataType == RS_TYPE_MATRIX_3X3) {
+        glUniformMatrix3fv(slot, arraySize, GL_FALSE, fd);
+    } else if (dataType == RS_TYPE_MATRIX_2X2) {
+        glUniformMatrix2fv(slot, arraySize, GL_FALSE, fd);
+    } else {
+        switch (field->getComponent().getVectorSize()) {
+        case 1:
+            glUniform1fv(slot, arraySize, fd);
+            break;
+        case 2:
+            glUniform2fv(slot, arraySize, fd);
+            break;
+        case 3:
+            glUniform3fv(slot, arraySize, fd);
+            break;
+        case 4:
+            glUniform4fv(slot, arraySize, fd);
+            break;
+        default:
+            rsAssert(0);
+        }
+    }
+}
+
+void RsdShader::setupSampler(const Context *rsc, const Sampler *s, const Allocation *tex) {
+    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+
+    GLenum trans[] = {
+        GL_NEAREST, //RS_SAMPLER_NEAREST,
+        GL_LINEAR, //RS_SAMPLER_LINEAR,
+        GL_LINEAR_MIPMAP_LINEAR, //RS_SAMPLER_LINEAR_MIP_LINEAR,
+        GL_REPEAT, //RS_SAMPLER_WRAP,
+        GL_CLAMP_TO_EDGE, //RS_SAMPLER_CLAMP
+        GL_LINEAR_MIPMAP_NEAREST, //RS_SAMPLER_LINEAR_MIP_NEAREST
+    };
+
+    GLenum transNP[] = {
+        GL_NEAREST, //RS_SAMPLER_NEAREST,
+        GL_LINEAR, //RS_SAMPLER_LINEAR,
+        GL_LINEAR, //RS_SAMPLER_LINEAR_MIP_LINEAR,
+        GL_CLAMP_TO_EDGE, //RS_SAMPLER_WRAP,
+        GL_CLAMP_TO_EDGE, //RS_SAMPLER_CLAMP
+        GL_LINEAR, //RS_SAMPLER_LINEAR_MIP_NEAREST,
+    };
+
+    // This tells us the correct texture type
+    GLenum target = (GLenum)tex->getGLTarget();
+
+    if (!dc->gl.gl.OES_texture_npot && tex->getType()->getIsNp2()) {
+        if (tex->getHasGraphicsMipmaps() &&
+            (dc->gl.gl.GL_NV_texture_npot_2D_mipmap || dc->gl.gl.GL_IMG_texture_npot)) {
+            if (dc->gl.gl.GL_NV_texture_npot_2D_mipmap) {
+                glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[s->mHal.state.minFilter]);
+            } else {
+                switch (trans[s->mHal.state.minFilter]) {
+                case GL_LINEAR_MIPMAP_LINEAR:
+                    glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+                    break;
+                default:
+                    glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[s->mHal.state.minFilter]);
+                    break;
+                }
+            }
+        } else {
+            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[s->mHal.state.minFilter]);
+        }
+        glTexParameteri(target, GL_TEXTURE_MAG_FILTER, transNP[s->mHal.state.magFilter]);
+        glTexParameteri(target, GL_TEXTURE_WRAP_S, transNP[s->mHal.state.wrapS]);
+        glTexParameteri(target, GL_TEXTURE_WRAP_T, transNP[s->mHal.state.wrapT]);
+    } else {
+        if (tex->getHasGraphicsMipmaps()) {
+            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[s->mHal.state.minFilter]);
+        } else {
+            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[s->mHal.state.minFilter]);
+        }
+        glTexParameteri(target, GL_TEXTURE_MAG_FILTER, trans[s->mHal.state.magFilter]);
+        glTexParameteri(target, GL_TEXTURE_WRAP_S, trans[s->mHal.state.wrapS]);
+        glTexParameteri(target, GL_TEXTURE_WRAP_T, trans[s->mHal.state.wrapT]);
+    }
+
+    float anisoValue = rsMin(dc->gl.gl.EXT_texture_max_aniso, s->mHal.state.aniso);
+    if (dc->gl.gl.EXT_texture_max_aniso > 1.0f) {
+        glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoValue);
+    }
+
+    rsc->checkError("Sampler::setupGL2 tex env");
+}
+
+void RsdShader::setupTextures(const Context *rsc, RsdShaderCache *sc) {
+    if (mRSProgram->mHal.state.texturesCount == 0) {
+        return;
+    }
+
+    uint32_t numTexturesToBind = mRSProgram->mHal.state.texturesCount;
+    uint32_t numTexturesAvailable = rsc->getMaxFragmentTextures();
+    if (numTexturesToBind >= numTexturesAvailable) {
+        LOGE("Attempting to bind %u textures on shader id %u, but only %u are available",
+             mRSProgram->mHal.state.texturesCount, (uint32_t)this, numTexturesAvailable);
+        rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind more textuers than available");
+        numTexturesToBind = numTexturesAvailable;
+    }
+
+    for (uint32_t ct=0; ct < numTexturesToBind; ct++) {
+        glActiveTexture(GL_TEXTURE0 + ct);
+        if (!mRSProgram->mHal.state.textures[ct].get()) {
+            LOGE("No texture bound for shader id %u, texture unit %u", (uint)this, ct);
+            rsc->setError(RS_ERROR_BAD_SHADER, "No texture bound");
+            continue;
+        }
+
+        GLenum target = (GLenum)mRSProgram->mHal.state.textures[ct]->getGLTarget();
+        if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) {
+            LOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", (uint)this, ct);
+            rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader");
+        }
+        glBindTexture(target, mRSProgram->mHal.state.textures[ct]->getTextureID());
+        rsc->checkError("ProgramFragment::setupGL2 tex bind");
+        if (mRSProgram->mHal.state.samplers[ct].get()) {
+            setupSampler(rsc, mRSProgram->mHal.state.samplers[ct].get(), mRSProgram->mHal.state.textures[ct].get());
+        } else {
+            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+            glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+            glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+            glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+            rsc->checkError("ProgramFragment::setupGL2 tex env");
+        }
+
+        glUniform1i(sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct);
+        rsc->checkError("ProgramFragment::setupGL2 uniforms");
+    }
+
+    glActiveTexture(GL_TEXTURE0);
+    mDirty = false;
+    rsc->checkError("ProgramFragment::setupGL2");
+}
+
+void RsdShader::setupUserConstants(const Context *rsc, RsdShaderCache *sc, bool isFragment) {
+    uint32_t uidx = 0;
+    for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
+        Allocation *alloc = mRSProgram->mHal.state.constants[ct].get();
+        if (!alloc) {
+            LOGE("Attempting to set constants on shader id %u, but alloc at slot %u is not set", (uint32_t)this, ct);
+            rsc->setError(RS_ERROR_BAD_SHADER, "No constant allocation bound");
+            continue;
+        }
+
+        const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr());
+        const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement();
+        for (uint32_t field=0; field < e->getFieldCount(); field++) {
+            const Element *f = e->getField(field);
+            const char *fieldName = e->getFieldName(field);
+            // If this field is padding, skip it
+            if (fieldName[0] == '#') {
+                continue;
+            }
+
+            uint32_t offset = e->getFieldOffsetBytes(field);
+            const float *fd = reinterpret_cast<const float *>(&data[offset]);
+
+            int32_t slot = -1;
+            uint32_t arraySize = 1;
+            if (!isFragment) {
+                slot = sc->vtxUniformSlot(uidx);
+                arraySize = sc->vtxUniformSize(uidx);
+            } else {
+                slot = sc->fragUniformSlot(uidx);
+                arraySize = sc->fragUniformSize(uidx);
+            }
+            if (rsc->props.mLogShadersUniforms) {
+                LOGV("Uniform  slot=%i, offset=%i, constant=%i, field=%i, uidx=%i, name=%s", slot, offset, ct, field, uidx, fieldName);
+            }
+            uidx ++;
+            if (slot < 0) {
+                continue;
+            }
+
+            if (rsc->props.mLogShadersUniforms) {
+                logUniform(f, fd, arraySize);
+            }
+            setUniform(rsc, f, fd, slot, arraySize);
+        }
+    }
+}
+
+void RsdShader::setup(const android::renderscript::Context *rsc, RsdShaderCache *sc) {
+
+    setupUserConstants(rsc, sc, mType == GL_FRAGMENT_SHADER);
+    setupTextures(rsc, sc);
+}
+
+void RsdShader::initAttribAndUniformArray() {
+    mAttribCount = 0;
+    for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
+        const Element *elem = mRSProgram->mHal.state.inputElements[ct].get();
+        for (uint32_t field=0; field < elem->getFieldCount(); field++) {
+            if (elem->getFieldName(field)[0] != '#') {
+                mAttribCount ++;
+            }
+        }
+    }
+
+    mUniformCount = 0;
+    for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
+        const Element *elem = mRSProgram->mHal.state.constantTypes[ct]->getElement();
+
+        for (uint32_t field=0; field < elem->getFieldCount(); field++) {
+            if (elem->getFieldName(field)[0] != '#') {
+                mUniformCount ++;
+            }
+        }
+    }
+    mUniformCount += mRSProgram->mHal.state.texturesCount;
+
+    if (mAttribCount) {
+        mAttribNames = new String8[mAttribCount];
+    }
+    if (mUniformCount) {
+        mUniformNames = new String8[mUniformCount];
+        mUniformArraySizes = new uint32_t[mUniformCount];
+    }
+}
+
+void RsdShader::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix) {
+    rsAssert(e->getFieldCount());
+    for (uint32_t ct=0; ct < e->getFieldCount(); ct++) {
+        const Element *ce = e->getField(ct);
+        if (ce->getFieldCount()) {
+            initAddUserElement(ce, names, arrayLengths, count, prefix);
+        } else if (e->getFieldName(ct)[0] != '#') {
+            String8 tmp(prefix);
+            tmp.append(e->getFieldName(ct));
+            names[*count].setTo(tmp.string());
+            if (arrayLengths) {
+                arrayLengths[*count] = e->getFieldArraySize(ct);
+            }
+            (*count)++;
+        }
+    }
+}
diff --git a/libs/rs/driver/rsdShader.h b/libs/rs/driver/rsdShader.h
new file mode 100644
index 0000000..63c4231
--- /dev/null
+++ b/libs/rs/driver/rsdShader.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2011 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_RSD_SHADER_H
+#define ANDROID_RSD_SHADER_H
+
+#include <utils/String8.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Element;
+class Context;
+class Program;
+
+}
+}
+
+class RsdShaderCache;
+
+#define RS_SHADER_ATTR "ATTRIB_"
+#define RS_SHADER_UNI "UNI_"
+
+class RsdShader {
+public:
+
+    RsdShader(const android::renderscript::Program *p, uint32_t type,
+               const char * shaderText, uint32_t shaderLength);
+    virtual ~RsdShader();
+
+    bool createShader();
+
+    uint32_t getShaderID() const {return mShaderID;}
+
+    uint32_t getAttribCount() const {return mAttribCount;}
+    uint32_t getUniformCount() const {return mUniformCount;}
+    const android::String8 & getAttribName(uint32_t i) const {return mAttribNames[i];}
+    const android::String8 & getUniformName(uint32_t i) const {return mUniformNames[i];}
+    uint32_t getUniformArraySize(uint32_t i) const {return mUniformArraySizes[i];}
+
+    android::String8 getGLSLInputString() const;
+
+    bool isValid() const {return mIsValid;}
+    void forceDirty() const {mDirty = true;}
+
+    bool loadShader(const android::renderscript::Context *);
+    void setup(const android::renderscript::Context *, RsdShaderCache *sc);
+
+protected:
+
+    const android::renderscript::Program *mRSProgram;
+    bool mIsValid;
+
+    // Applies to vertex and fragment shaders only
+    void appendUserConstants();
+    void setupUserConstants(const android::renderscript::Context *rsc, RsdShaderCache *sc, bool isFragment);
+    void initAddUserElement(const android::renderscript::Element *e, android::String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix);
+    void setupTextures(const android::renderscript::Context *rsc, RsdShaderCache *sc);
+    void setupSampler(const android::renderscript::Context *rsc, const android::renderscript::Sampler *s, const android::renderscript::Allocation *tex);
+
+    void appendAttributes();
+    void appendTextures();
+
+    void initAttribAndUniformArray();
+
+    mutable bool mDirty;
+    android::String8 mShader;
+    android::String8 mUserShader;
+    uint32_t mShaderID;
+    uint32_t mType;
+
+    uint32_t mTextureCount;
+    uint32_t mAttribCount;
+    uint32_t mUniformCount;
+    android::String8 *mAttribNames;
+    android::String8 *mUniformNames;
+    uint32_t *mUniformArraySizes;
+
+    int32_t mTextureUniformIndexStart;
+
+    void logUniform(const android::renderscript::Element *field, const float *fd, uint32_t arraySize );
+    void setUniform(const android::renderscript::Context *rsc, const android::renderscript::Element *field, const float *fd, int32_t slot, uint32_t arraySize );
+    void initMemberVars();
+    void init();
+};
+
+#endif //ANDROID_RSD_SHADER_H
+
+
+
+
diff --git a/libs/rs/rsShaderCache.cpp b/libs/rs/driver/rsdShaderCache.cpp
similarity index 81%
rename from libs/rs/rsShaderCache.cpp
rename to libs/rs/driver/rsdShaderCache.cpp
index e8d89c2..18a8225 100644
--- a/libs/rs/rsShaderCache.cpp
+++ b/libs/rs/driver/rsdShaderCache.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -14,25 +14,30 @@
  * limitations under the License.
  */
 
-#include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
+#include <rs_hal.h>
+#include <rsContext.h>
+
+#include "rsdShader.h"
+#include "rsdShaderCache.h"
+
 #include <GLES/gl.h>
 #include <GLES2/gl2.h>
-#endif //ANDROID_RS_SERIALIZE
 
 using namespace android;
 using namespace android::renderscript;
 
 
-ShaderCache::ShaderCache() {
+RsdShaderCache::RsdShaderCache() {
     mEntries.setCapacity(16);
+    mVertexDirty = true;
+    mFragmentDirty = true;
 }
 
-ShaderCache::~ShaderCache() {
+RsdShaderCache::~RsdShaderCache() {
     cleanupAll();
 }
 
-void ShaderCache::updateUniformArrayData(Context *rsc, Program *prog, uint32_t linkedID,
+void RsdShaderCache::updateUniformArrayData(const Context *rsc, RsdShader *prog, uint32_t linkedID,
                                          UniformData *data, const char* logTag,
                                          UniformQueryData **uniformList, uint32_t uniListSize) {
 
@@ -54,14 +59,14 @@
     }
 }
 
-void ShaderCache::populateUniformData(Program *prog, uint32_t linkedID, UniformData *data) {
+void RsdShaderCache::populateUniformData(RsdShader *prog, uint32_t linkedID, UniformData *data) {
     for (uint32_t ct=0; ct < prog->getUniformCount(); ct++) {
        data[ct].slot = glGetUniformLocation(linkedID, prog->getUniformName(ct));
        data[ct].arraySize = prog->getUniformArraySize(ct);
     }
 }
 
-bool ShaderCache::hasArrayUniforms(ProgramVertex *vtx, ProgramFragment *frag) {
+bool RsdShaderCache::hasArrayUniforms(RsdShader *vtx, RsdShader *frag) {
     UniformData *data = mCurrent->vtxUniforms;
     for (uint32_t ct=0; ct < vtx->getUniformCount(); ct++) {
         if (data[ct].slot >= 0 && data[ct].arraySize > 1) {
@@ -77,7 +82,31 @@
     return false;
 }
 
-bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag) {
+bool RsdShaderCache::setup(const Context *rsc) {
+    if (!mVertexDirty && !mFragmentDirty) {
+        return true;
+    }
+
+    if (!link(rsc)) {
+        return false;
+    }
+
+    if (mFragmentDirty) {
+        mFragment->setup(rsc, this);
+        mFragmentDirty = false;
+    }
+    if (mVertexDirty) {
+        mVertex->setup(rsc, this);
+        mVertexDirty = false;
+    }
+
+    return true;
+}
+
+bool RsdShaderCache::link(const Context *rsc) {
+
+    RsdShader *vtx = mVertex;
+    RsdShader *frag = mFragment;
     if (!vtx->getShaderID()) {
         vtx->loadShader(rsc);
     }
@@ -89,7 +118,7 @@
     if (!vtx->getShaderID() || !frag->getShaderID()) {
         return false;
     }
-    //LOGV("ShaderCache lookup  vtx %i, frag %i", vtx->getShaderID(), frag->getShaderID());
+    //LOGV("rsdShaderCache lookup  vtx %i, frag %i", vtx->getShaderID(), frag->getShaderID());
     uint32_t entryCount = mEntries.size();
     for (uint32_t ct = 0; ct < entryCount; ct ++) {
         if ((mEntries[ct]->vtx == vtx->getShaderID()) &&
@@ -98,13 +127,13 @@
             //LOGV("SC using program %i", mEntries[ct]->program);
             glUseProgram(mEntries[ct]->program);
             mCurrent = mEntries[ct];
-            //LOGV("ShaderCache hit, using %i", ct);
-            rsc->checkError("ShaderCache::lookup (hit)");
+            //LOGV("RsdShaderCache hit, using %i", ct);
+            rsc->checkError("RsdShaderCache::link (hit)");
             return true;
         }
     }
 
-    //LOGV("ShaderCache miss");
+    //LOGV("RsdShaderCache miss");
     //LOGE("e0 %x", glGetError());
     ProgramEntry *e = new ProgramEntry(vtx->getAttribCount(),
                                        vtx->getUniformCount(),
@@ -120,12 +149,10 @@
         //LOGE("e1 %x", glGetError());
         glAttachShader(pgm, frag->getShaderID());
 
-        if (!vtx->isUserProgram()) {
-            glBindAttribLocation(pgm, 0, "ATTRIB_position");
-            glBindAttribLocation(pgm, 1, "ATTRIB_color");
-            glBindAttribLocation(pgm, 2, "ATTRIB_normal");
-            glBindAttribLocation(pgm, 3, "ATTRIB_texture0");
-        }
+        glBindAttribLocation(pgm, 0, "ATTRIB_position");
+        glBindAttribLocation(pgm, 1, "ATTRIB_color");
+        glBindAttribLocation(pgm, 2, "ATTRIB_normal");
+        glBindAttribLocation(pgm, 3, "ATTRIB_texture0");
 
         //LOGE("e2 %x", glGetError());
         glLinkProgram(pgm);
@@ -203,11 +230,12 @@
 
     //LOGV("SC made program %i", e->program);
     glUseProgram(e->program);
-    rsc->checkError("ShaderCache::lookup (miss)");
+    rsc->checkError("RsdShaderCache::link (miss)");
+
     return true;
 }
 
-int32_t ShaderCache::vtxAttribSlot(const String8 &attrName) const {
+int32_t RsdShaderCache::vtxAttribSlot(const String8 &attrName) const {
     for (uint32_t ct=0; ct < mCurrent->vtxAttrCount; ct++) {
         if (attrName == mCurrent->vtxAttrs[ct].name) {
             return mCurrent->vtxAttrs[ct].slot;
@@ -216,7 +244,7 @@
     return -1;
 }
 
-void ShaderCache::cleanupVertex(uint32_t id) {
+void RsdShaderCache::cleanupVertex(uint32_t id) {
     int32_t numEntries = (int32_t)mEntries.size();
     for (int32_t ct = 0; ct < numEntries; ct ++) {
         if (mEntries[ct]->vtx == id) {
@@ -230,7 +258,7 @@
     }
 }
 
-void ShaderCache::cleanupFragment(uint32_t id) {
+void RsdShaderCache::cleanupFragment(uint32_t id) {
     int32_t numEntries = (int32_t)mEntries.size();
     for (int32_t ct = 0; ct < numEntries; ct ++) {
         if (mEntries[ct]->frag == id) {
@@ -244,7 +272,7 @@
     }
 }
 
-void ShaderCache::cleanupAll() {
+void RsdShaderCache::cleanupAll() {
     for (uint32_t ct=0; ct < mEntries.size(); ct++) {
         glDeleteProgram(mEntries[ct]->program);
         free(mEntries[ct]);
diff --git a/libs/rs/rsShaderCache.h b/libs/rs/driver/rsdShaderCache.h
similarity index 74%
rename from libs/rs/rsShaderCache.h
rename to libs/rs/driver/rsdShaderCache.h
index 3540366..17ee3e8 100644
--- a/libs/rs/rsShaderCache.h
+++ b/libs/rs/driver/rsdShaderCache.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -14,38 +14,59 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_SHADER_CACHE_H
-#define ANDROID_SHADER_CACHE_H
+#ifndef ANDROID_RSD_SHADER_CACHE_H
+#define ANDROID_RSD_SHADER_CACHE_H
 
-
-#include "rsObjectBase.h"
-#include "rsVertexArray.h"
-
-// ---------------------------------------------------------------------------
 namespace android {
 namespace renderscript {
 
+class Context;
+
+}
+}
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+class RsdShader;
+
+// ---------------------------------------------------------------------------
 
 // An element is a group of Components that occupies one cell in a structure.
-class ShaderCache {
+class RsdShaderCache {
 public:
-    ShaderCache();
-    virtual ~ShaderCache();
+    RsdShaderCache();
+    virtual ~RsdShaderCache();
 
-    bool lookup(Context *rsc, ProgramVertex *, ProgramFragment *);
+    void setActiveVertex(RsdShader *pv) {
+        mVertexDirty = true;
+        mVertex = pv;
+    }
+
+    void setActiveFragment(RsdShader *pf) {
+        mFragmentDirty = true;
+        mFragment = pf;
+    }
+
+    bool setup(const android::renderscript::Context *rsc);
 
     void cleanupVertex(uint32_t id);
     void cleanupFragment(uint32_t id);
 
     void cleanupAll();
 
-    int32_t vtxAttribSlot(const String8 &attrName) const;
+    int32_t vtxAttribSlot(const android::String8 &attrName) const;
     int32_t vtxUniformSlot(uint32_t a) const {return mCurrent->vtxUniforms[a].slot;}
     uint32_t vtxUniformSize(uint32_t a) const {return mCurrent->vtxUniforms[a].arraySize;}
     int32_t fragUniformSlot(uint32_t a) const {return mCurrent->fragUniforms[a].slot;}
     uint32_t fragUniformSize(uint32_t a) const {return mCurrent->fragUniforms[a].arraySize;}
 
 protected:
+    bool link(const android::renderscript::Context *rsc);
+    bool mFragmentDirty;
+    bool mVertexDirty;
+    RsdShader *mVertex;
+    RsdShader *mFragment;
+
     struct UniformQueryData {
         char *name;
         uint32_t nameLength;
@@ -111,21 +132,19 @@
         UniformData *vtxUniforms;
         UniformData *fragUniforms;
     };
-    Vector<ProgramEntry*> mEntries;
+    android::Vector<ProgramEntry*> mEntries;
     ProgramEntry *mCurrent;
 
-    bool hasArrayUniforms(ProgramVertex *vtx, ProgramFragment *frag);
-    void populateUniformData(Program *prog, uint32_t linkedID, UniformData *data);
-    void updateUniformArrayData(Context *rsc, Program *prog, uint32_t linkedID,
+    bool hasArrayUniforms(RsdShader *vtx, RsdShader *frag);
+    void populateUniformData(RsdShader *prog, uint32_t linkedID, UniformData *data);
+    void updateUniformArrayData(const android::renderscript::Context *rsc,
+                                RsdShader *prog, uint32_t linkedID,
                                 UniformData *data, const char* logTag,
                                 UniformQueryData **uniformList, uint32_t uniListSize);
 };
 
 
-
-}
-}
-#endif //ANDROID_SHADER_CACHE_H
+#endif //ANDROID_RSD_SHADER_CACHE_H
 
 
 
diff --git a/libs/rs/rsVertexArray.cpp b/libs/rs/driver/rsdVertexArray.cpp
similarity index 73%
rename from libs/rs/rsVertexArray.cpp
rename to libs/rs/driver/rsdVertexArray.cpp
index 354ee89..d0a5a54 100644
--- a/libs/rs/rsVertexArray.cpp
+++ b/libs/rs/driver/rsdVertexArray.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -14,28 +14,32 @@
  * limitations under the License.
  */
 
-#include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
+#include <rs_hal.h>
+#include <rsContext.h>
+
 #include <GLES/gl.h>
 #include <GLES2/gl2.h>
-#endif
+
+#include "rsdCore.h"
+#include "rsdVertexArray.h"
+#include "rsdShaderCache.h"
 
 using namespace android;
 using namespace android::renderscript;
 
-VertexArray::VertexArray(const Attrib *attribs, uint32_t numAttribs) {
+RsdVertexArray::RsdVertexArray(const Attrib *attribs, uint32_t numAttribs) {
     mAttribs = attribs;
     mCount = numAttribs;
 }
 
-VertexArray::~VertexArray() {
+RsdVertexArray::~RsdVertexArray() {
 }
 
-VertexArray::Attrib::Attrib() {
+RsdVertexArray::Attrib::Attrib() {
     clear();
 }
 
-void VertexArray::Attrib::clear() {
+void RsdVertexArray::Attrib::clear() {
     buffer = 0;
     offset = 0;
     type = 0;
@@ -46,7 +50,7 @@
     name.setTo("");
 }
 
-void VertexArray::Attrib::set(uint32_t type, uint32_t size, uint32_t stride,
+void RsdVertexArray::Attrib::set(uint32_t type, uint32_t size, uint32_t stride,
                               bool normalized, uint32_t offset,
                               const char *name) {
     clear();
@@ -58,7 +62,7 @@
     this->name.setTo(name);
 }
 
-void VertexArray::logAttrib(uint32_t idx, uint32_t slot) const {
+void RsdVertexArray::logAttrib(uint32_t idx, uint32_t slot) const {
     if (idx == 0) {
         LOGV("Starting vertex attribute binding");
     }
@@ -74,11 +78,15 @@
          mAttribs[idx].offset);
 }
 
-void VertexArray::setupGL2(const Context *rsc,
-                           class VertexArrayState *state,
-                           ShaderCache *sc) const {
-    rsc->checkError("VertexArray::setupGL2 start");
+void RsdVertexArray::setupGL2(const Context *rsc) const {
+
+    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+    RsdVertexArrayState *state = dc->gl.vertexArrayState;
+    RsdShaderCache *sc = dc->gl.shaderCache;
+
+    rsc->checkError("RsdVertexArray::setupGL2 start");
     uint32_t maxAttrs = state->mAttrsEnabledSize;
+
     for (uint32_t ct=1; ct < maxAttrs; ct++) {
         if(state->mAttrsEnabled[ct]) {
             glDisableVertexAttribArray(ct);
@@ -86,7 +94,7 @@
         }
     }
 
-    rsc->checkError("VertexArray::setupGL2 disabled");
+    rsc->checkError("RsdVertexArray::setupGL2 disabled");
     for (uint32_t ct=0; ct < mCount; ct++) {
         int32_t slot = sc->vtxAttribSlot(mAttribs[ct].name);
         if (rsc->props.mLogShadersAttr) {
@@ -105,22 +113,22 @@
                               mAttribs[ct].stride,
                               mAttribs[ct].ptr + mAttribs[ct].offset);
     }
-    rsc->checkError("VertexArray::setupGL2 done");
+    rsc->checkError("RsdVertexArray::setupGL2 done");
 }
 ////////////////////////////////////////////
-VertexArrayState::VertexArrayState() {
+RsdVertexArrayState::RsdVertexArrayState() {
     mAttrsEnabled = NULL;
     mAttrsEnabledSize = 0;
 }
 
-VertexArrayState::~VertexArrayState() {
+RsdVertexArrayState::~RsdVertexArrayState() {
     if (mAttrsEnabled) {
         delete[] mAttrsEnabled;
         mAttrsEnabled = NULL;
     }
 }
-void VertexArrayState::init(Context *rsc) {
-    mAttrsEnabledSize = rsc->getMaxVertexAttributes();
+void RsdVertexArrayState::init(uint32_t maxAttrs) {
+    mAttrsEnabledSize = maxAttrs;
     mAttrsEnabled = new bool[mAttrsEnabledSize];
     for (uint32_t ct = 0; ct < mAttrsEnabledSize; ct++) {
         mAttrsEnabled[ct] = false;
diff --git a/libs/rs/rsVertexArray.h b/libs/rs/driver/rsdVertexArray.h
similarity index 69%
rename from libs/rs/rsVertexArray.h
rename to libs/rs/driver/rsdVertexArray.h
index 45d9e82..925a6ae 100644
--- a/libs/rs/rsVertexArray.h
+++ b/libs/rs/driver/rsdVertexArray.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -14,20 +14,21 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_VERTEX_ARRAY_H
-#define ANDROID_VERTEX_ARRAY_H
+#ifndef ANDROID_RSD_VERTEX_ARRAY_H
+#define ANDROID_RSD_VERTEX_ARRAY_H
 
-
-#include "rsObjectBase.h"
-
-// ---------------------------------------------------------------------------
 namespace android {
 namespace renderscript {
 
-class ShaderCache;
+class Context;
+
+}
+}
+
+#include <utils/String8.h>
 
 // An element is a group of Components that occupies one cell in a structure.
-class VertexArray {
+class RsdVertexArray {
 public:
     class Attrib {
     public:
@@ -38,17 +39,17 @@
         uint32_t size;
         uint32_t stride;
         bool normalized;
-        String8 name;
+        android::String8 name;
 
         Attrib();
         void clear();
         void set(uint32_t type, uint32_t size, uint32_t stride, bool normalized, uint32_t offset, const char *name);
     };
 
-    VertexArray(const Attrib *attribs, uint32_t numAttribs);
-    virtual ~VertexArray();
+    RsdVertexArray(const Attrib *attribs, uint32_t numAttribs);
+    virtual ~RsdVertexArray();
 
-    void setupGL2(const Context *rsc, class VertexArrayState *, ShaderCache *) const;
+    void setupGL2(const android::renderscript::Context *rsc) const;
     void logAttrib(uint32_t idx, uint32_t slot) const;
 
 protected:
@@ -61,20 +62,18 @@
 };
 
 
-class VertexArrayState {
+class RsdVertexArrayState {
 public:
-    VertexArrayState();
-    ~VertexArrayState();
-    void init(Context *);
+    RsdVertexArrayState();
+    ~RsdVertexArrayState();
+    void init(uint32_t maxAttrs);
 
     bool *mAttrsEnabled;
     uint32_t mAttrsEnabledSize;
 };
 
 
-}
-}
-#endif //ANDROID_VERTEX_ARRAY_H
+#endif //ANDROID_RSD_VERTEX_ARRAY_H
 
 
 
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 0c4e1ed..5370e25 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -250,24 +250,15 @@
 	param uint32_t dimY
 	}
 
-SamplerBegin {
-	}
-
-SamplerSet {
-	param RsSamplerParam p
-	param RsSamplerValue value
-	}
-
-SamplerSet2 {
-	param RsSamplerParam p
-	param float value
-	}
-
 SamplerCreate {
-	ret RsSampler
-	}
-
-
+    param RsSamplerValue magFilter
+    param RsSamplerValue minFilter
+    param RsSamplerValue wrapS
+    param RsSamplerValue wrapT
+    param RsSamplerValue wrapR
+    param float mAniso
+    ret RsSampler
+}
 
 ScriptBindAllocation {
 	param RsScript vtm
@@ -275,13 +266,11 @@
 	param uint32_t slot
 	}
 
-
 ScriptSetTimeZone {
 	param RsScript s
 	param const char * timeZone
 	}
 
-
 ScriptInvoke {
 	param RsScript s
 	param uint32_t slot
@@ -293,7 +282,7 @@
 	param const void * data
 	}
 
-ScriptForEach { 
+ScriptForEach {
     param RsScript s
     param uint32_t slot
     param RsAllocation ain
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 4321592..e2e14f2 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -215,15 +215,11 @@
 }
 
 bool Context::setupCheck() {
-    if (!mShaderCache.lookup(this, mVertex.get(), mFragment.get())) {
-        LOGE("Context::setupCheck() 1 fail");
-        return false;
-    }
 
     mFragmentStore->setup(this, &mStateFragmentStore);
-    mFragment->setupGL2(this, &mStateFragment, &mShaderCache);
+    mFragment->setupGL2(this, &mStateFragment);
     mRaster->setup(this, &mStateRaster);
-    mVertex->setupGL2(this, &mStateVertex, &mShaderCache);
+    mVertex->setupGL2(this, &mStateVertex);
     mFBOCache.setupGL2(this);
     return true;
 }
@@ -274,17 +270,18 @@
     rsc->props.mLogVisual = getProp("debug.rs.visual");
 
     if (!rsdHalInit(rsc, 0, 0)) {
+        rsc->setError(RS_ERROR_FATAL_DRIVER, "Failed initializing GL");
         LOGE("Hal init failed");
         return NULL;
     }
     rsc->mHal.funcs.setPriority(rsc, rsc->mThreadPriority);
 
-    if (!rsc->initGLThread()) {
-        rsc->setError(RS_ERROR_OUT_OF_MEMORY, "Failed initializing GL");
-        return NULL;
-    }
-
     if (rsc->mIsGraphicsContext) {
+        if (!rsc->initGLThread()) {
+            rsc->setError(RS_ERROR_OUT_OF_MEMORY, "Failed initializing GL");
+            return NULL;
+        }
+
         rsc->mStateRaster.init(rsc);
         rsc->setProgramRaster(NULL);
         rsc->mStateVertex.init(rsc);
@@ -295,7 +292,6 @@
         rsc->setProgramStore(NULL);
         rsc->mStateFont.init(rsc);
         rsc->setFont(NULL);
-        rsc->mStateVertexArray.init(rsc);
     }
 
     rsc->mRunning = true;
@@ -356,7 +352,6 @@
          mStateFragment.deinit(this);
          mStateFragmentStore.deinit(this);
          mStateFont.deinit(this);
-         mShaderCache.cleanupAll();
     }
     //LOGV("destroyWorkerThreadResources 2");
     mExit = true;
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index df85a6b..107f639 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -37,9 +37,7 @@
 #include "rsProgramStore.h"
 #include "rsProgramRaster.h"
 #include "rsProgramVertex.h"
-#include "rsShaderCache.h"
 #include "rsFBOCache.h"
-#include "rsVertexArray.h"
 
 #include "rsgApiStructs.h"
 #include "rsLocklessFifo.h"
@@ -111,11 +109,9 @@
     ProgramStoreState mStateFragmentStore;
     ProgramRasterState mStateRaster;
     ProgramVertexState mStateVertex;
-    VertexArrayState mStateVertexArray;
     FontState mStateFont;
 
     ScriptCState mScriptC;
-    ShaderCache mShaderCache;
     FBOCache mFBOCache;
 
     void swapBuffers();
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp
index b7b85b6..5e47ddb 100644
--- a/libs/rs/rsFont.cpp
+++ b/libs/rs/rsFont.cpp
@@ -25,11 +25,6 @@
 #include FT_FREETYPE_H
 #include FT_BITMAP_H
 
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
 using namespace android;
 using namespace android::renderscript;
 
@@ -457,7 +452,7 @@
 
     // This will dirty the texture and the shader so next time
     // we draw it will upload the data
-    mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
+    mTextTexture->deferredUploadToTexture(mRSC);
     mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
 
     // Some debug code
@@ -568,7 +563,6 @@
     }
 
     indexAlloc->deferredUploadToBufferObject(mRSC);
-    mIndexBuffer.set(indexAlloc);
 
     const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
     const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
@@ -585,7 +579,10 @@
     Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
     mTextMeshPtr = (float*)vertexAlloc->getPtr();
 
-    mVertexArray.set(vertexAlloc);
+    mMesh.set(new Mesh(mRSC, 1, 1));
+    mMesh->setVertexBuffer(vertexAlloc, 0);
+    mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
+    mMesh->init();
 }
 
 // We don't want to allocate anything unless we actually draw text
@@ -625,18 +622,7 @@
         return;
     }
 
-    float *vtx = (float*)mVertexArray->getPtr();
-    float *tex = vtx + 3;
-
-    VertexArray::Attrib attribs[2];
-    attribs[0].set(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
-    attribs[1].set(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
-    VertexArray va(attribs, 2);
-    va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
-
-    mIndexBuffer->uploadCheck(mRSC);
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
-    glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
+    mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
 }
 
 void FontState::appendMeshQuad(float x1, float y1, float z1,
@@ -787,8 +773,7 @@
 
     mFontShaderFConstant.clear();
 
-    mIndexBuffer.clear();
-    mVertexArray.clear();
+    mMesh.clear();
 
     mFontShaderF.clear();
     mFontSampler.clear();
diff --git a/libs/rs/rsFont.h b/libs/rs/rsFont.h
index 91a5da9..d18c0d9 100644
--- a/libs/rs/rsFont.h
+++ b/libs/rs/rsFont.h
@@ -230,9 +230,7 @@
     uint32_t mMaxNumberOfQuads;
 
     void initVertexArrayBuffers();
-    ObjectBaseRef<Allocation> mIndexBuffer;
-    ObjectBaseRef<Allocation> mVertexArray;
-
+    ObjectBaseRef<Mesh> mMesh;
 
     bool mInitialized;
 
diff --git a/libs/rs/rsMesh.cpp b/libs/rs/rsMesh.cpp
index e29c800..ed29063 100644
--- a/libs/rs/rsMesh.cpp
+++ b/libs/rs/rsMesh.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -15,46 +15,53 @@
  */
 
 #include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
-#include <GLES/gl.h>
-#include <GLES2/gl2.h>
-#include <GLES/glext.h>
-#endif
 
 using namespace android;
 using namespace android::renderscript;
 
 Mesh::Mesh(Context *rsc) : ObjectBase(rsc) {
-    mPrimitives = NULL;
-    mPrimitivesCount = 0;
-    mVertexBuffers = NULL;
-    mVertexBufferCount = 0;
+    mHal.drv = NULL;
+    mHal.state.primitives = NULL;
+    mHal.state.primitivesCount = 0;
+    mHal.state.vertexBuffers = NULL;
+    mHal.state.vertexBuffersCount = 0;
+    mInitialized = false;
+}
 
-#ifndef ANDROID_RS_SERIALIZE
-    mAttribs = NULL;
-    mAttribAllocationIndex = NULL;
-
-    mAttribCount = 0;
-#endif
+Mesh::Mesh(Context *rsc,
+           uint32_t vertexBuffersCount,
+           uint32_t primitivesCount) : ObjectBase(rsc) {
+    mHal.drv = NULL;
+    mHal.state.primitivesCount = primitivesCount;
+    mHal.state.primitives = new Primitive_t *[mHal.state.primitivesCount];
+    for (uint32_t i = 0; i < mHal.state.primitivesCount; i ++) {
+        mHal.state.primitives[i] = new Primitive_t;
+    }
+    mHal.state.vertexBuffersCount = vertexBuffersCount;
+    mHal.state.vertexBuffers = new ObjectBaseRef<Allocation>[mHal.state.vertexBuffersCount];
 }
 
 Mesh::~Mesh() {
-    if (mVertexBuffers) {
-        delete[] mVertexBuffers;
-    }
-
-    if (mPrimitives) {
-        for (uint32_t i = 0; i < mPrimitivesCount; i ++) {
-            delete mPrimitives[i];
-        }
-        delete[] mPrimitives;
-    }
-
 #ifndef ANDROID_RS_SERIALIZE
-    if (mAttribs) {
-        delete[] mAttribs;
-        delete[] mAttribAllocationIndex;
+    mRSC->mHal.funcs.mesh.destroy(mRSC, this);
+#endif
+
+    if (mHal.state.vertexBuffers) {
+        delete[] mHal.state.vertexBuffers;
     }
+
+    if (mHal.state.primitives) {
+        for (uint32_t i = 0; i < mHal.state.primitivesCount; i ++) {
+            mHal.state.primitives[i]->mIndexBuffer.clear();
+            delete mHal.state.primitives[i];
+        }
+        delete[] mHal.state.primitives;
+    }
+}
+
+void Mesh::init() {
+#ifndef ANDROID_RS_SERIALIZE
+    mRSC->mHal.funcs.mesh.init(mRSC, this);
 #endif
 }
 
@@ -66,15 +73,15 @@
     stream->addString(&name);
 
     // Store number of vertex streams
-    stream->addU32(mVertexBufferCount);
-    for (uint32_t vCount = 0; vCount < mVertexBufferCount; vCount ++) {
-        mVertexBuffers[vCount]->serialize(stream);
+    stream->addU32(mHal.state.vertexBuffersCount);
+    for (uint32_t vCount = 0; vCount < mHal.state.vertexBuffersCount; vCount ++) {
+        mHal.state.vertexBuffers[vCount]->serialize(stream);
     }
 
-    stream->addU32(mPrimitivesCount);
+    stream->addU32(mHal.state.primitivesCount);
     // Store the primitives
-    for (uint32_t pCount = 0; pCount < mPrimitivesCount; pCount ++) {
-        Primitive_t * prim = mPrimitives[pCount];
+    for (uint32_t pCount = 0; pCount < mHal.state.primitivesCount; pCount ++) {
+        Primitive_t * prim = mHal.state.primitives[pCount];
 
         stream->addU8((uint8_t)prim->mPrimitive);
 
@@ -95,45 +102,60 @@
         return NULL;
     }
 
-    Mesh * mesh = new Mesh(rsc);
-
     String8 name;
     stream->loadString(&name);
-    mesh->setName(name.string(), name.size());
 
-    mesh->mVertexBufferCount = stream->loadU32();
-    if (mesh->mVertexBufferCount) {
-        mesh->mVertexBuffers = new ObjectBaseRef<Allocation>[mesh->mVertexBufferCount];
+    uint32_t vertexBuffersCount = stream->loadU32();
+    ObjectBaseRef<Allocation> *vertexBuffers = NULL;
+    if (vertexBuffersCount) {
+        vertexBuffers = new ObjectBaseRef<Allocation>[vertexBuffersCount];
 
-        for (uint32_t vCount = 0; vCount < mesh->mVertexBufferCount; vCount ++) {
+        for (uint32_t vCount = 0; vCount < vertexBuffersCount; vCount ++) {
             Allocation *vertexAlloc = Allocation::createFromStream(rsc, stream);
-            mesh->mVertexBuffers[vCount].set(vertexAlloc);
+            vertexBuffers[vCount].set(vertexAlloc);
         }
     }
 
-    mesh->mPrimitivesCount = stream->loadU32();
-    if (mesh->mPrimitivesCount) {
-        mesh->mPrimitives = new Primitive_t *[mesh->mPrimitivesCount];
+    uint32_t primitivesCount = stream->loadU32();
+    ObjectBaseRef<Allocation> *indexBuffers = NULL;
+    RsPrimitive *primitives = NULL;
+    if (primitivesCount) {
+        indexBuffers = new ObjectBaseRef<Allocation>[primitivesCount];
+        primitives = new RsPrimitive[primitivesCount];
 
         // load all primitives
-        for (uint32_t pCount = 0; pCount < mesh->mPrimitivesCount; pCount ++) {
-            Primitive_t * prim = new Primitive_t;
-            mesh->mPrimitives[pCount] = prim;
-
-            prim->mPrimitive = (RsPrimitive)stream->loadU8();
+        for (uint32_t pCount = 0; pCount < primitivesCount; pCount ++) {
+            primitives[pCount] = (RsPrimitive)stream->loadU8();
 
             // Check to see if the index buffer was stored
             uint32_t isIndexPresent = stream->loadU32();
             if (isIndexPresent) {
                 Allocation *indexAlloc = Allocation::createFromStream(rsc, stream);
-                prim->mIndexBuffer.set(indexAlloc);
+                indexBuffers[pCount].set(indexAlloc);
             }
         }
     }
 
+    Mesh *mesh = new Mesh(rsc, vertexBuffersCount, primitivesCount);
+    mesh->setName(name.string(), name.size());
+    for (uint32_t vCount = 0; vCount < vertexBuffersCount; vCount ++) {
+        mesh->setVertexBuffer(vertexBuffers[vCount].get(), vCount);
+    }
+    for (uint32_t pCount = 0; pCount < primitivesCount; pCount ++) {
+        mesh->setPrimitive(indexBuffers[pCount].get(), primitives[pCount], pCount);
+    }
+
+    // Cleanup
+    if (vertexBuffersCount) {
+        delete[] vertexBuffers;
+    }
+    if (primitivesCount) {
+        delete[] indexBuffers;
+        delete[] primitives;
+    }
+
 #ifndef ANDROID_RS_SERIALIZE
-    mesh->updateGLPrimitives();
-    mesh->initVertexAttribs();
+    mesh->init();
     mesh->uploadAll(rsc);
 #endif
     return mesh;
@@ -141,167 +163,58 @@
 
 #ifndef ANDROID_RS_SERIALIZE
 
-bool Mesh::isValidGLComponent(const Element *elem, uint32_t fieldIdx) {
-    // Do not create attribs for padding
-    if (elem->getFieldName(fieldIdx)[0] == '#') {
-        return false;
-    }
-
-    // Only GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, GL_FLOAT are accepted.
-    // Filter rs types accordingly
-    RsDataType dt = elem->getField(fieldIdx)->getComponent().getType();
-    if (dt != RS_TYPE_FLOAT_32 && dt != RS_TYPE_UNSIGNED_8 &&
-       dt != RS_TYPE_UNSIGNED_16 && dt != RS_TYPE_SIGNED_8 &&
-       dt != RS_TYPE_SIGNED_16) {
-        return false;
-    }
-
-    // Now make sure they are not arrays
-    uint32_t arraySize = elem->getFieldArraySize(fieldIdx);
-    if (arraySize != 1) {
-        return false;
-    }
-
-    return true;
-}
-
-void Mesh::initVertexAttribs() {
-    // Count the number of gl attrs to initialize
-    mAttribCount = 0;
-    for (uint32_t ct=0; ct < mVertexBufferCount; ct++) {
-        const Element *elem = mVertexBuffers[ct]->getType()->getElement();
-        for (uint32_t ct=0; ct < elem->getFieldCount(); ct++) {
-            if (isValidGLComponent(elem, ct)) {
-                mAttribCount ++;
-            }
-        }
-    }
-
-    if (mAttribs) {
-        delete [] mAttribs;
-        delete [] mAttribAllocationIndex;
-        mAttribs = NULL;
-        mAttribAllocationIndex = NULL;
-    }
-    if (!mAttribCount) {
-        return;
-    }
-
-    mAttribs = new VertexArray::Attrib[mAttribCount];
-    mAttribAllocationIndex = new uint32_t[mAttribCount];
-
-    uint32_t userNum = 0;
-    for (uint32_t ct=0; ct < mVertexBufferCount; ct++) {
-        const Element *elem = mVertexBuffers[ct]->getType()->getElement();
-        uint32_t stride = elem->getSizeBytes();
-        for (uint32_t fieldI=0; fieldI < elem->getFieldCount(); fieldI++) {
-            const Component &c = elem->getField(fieldI)->getComponent();
-
-            if (!isValidGLComponent(elem, fieldI)) {
-                continue;
-            }
-
-            mAttribs[userNum].size = c.getVectorSize();
-            mAttribs[userNum].offset = elem->getFieldOffsetBytes(fieldI);
-            mAttribs[userNum].type = c.getGLType();
-            mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized();
-            mAttribs[userNum].stride = stride;
-            String8 tmp(RS_SHADER_ATTR);
-            tmp.append(elem->getFieldName(fieldI));
-            mAttribs[userNum].name.setTo(tmp.string());
-
-            // Remember which allocation this attribute came from
-            mAttribAllocationIndex[userNum] = ct;
-            userNum ++;
-        }
-    }
-}
-
 void Mesh::render(Context *rsc) const {
-    for (uint32_t ct = 0; ct < mPrimitivesCount; ct ++) {
+    for (uint32_t ct = 0; ct < mHal.state.primitivesCount; ct ++) {
         renderPrimitive(rsc, ct);
     }
 }
 
 void Mesh::renderPrimitive(Context *rsc, uint32_t primIndex) const {
-    if (primIndex >= mPrimitivesCount) {
+    if (primIndex >= mHal.state.primitivesCount) {
         LOGE("Invalid primitive index");
         return;
     }
 
-    Primitive_t *prim = mPrimitives[primIndex];
+    Primitive_t *prim = mHal.state.primitives[primIndex];
 
     if (prim->mIndexBuffer.get()) {
         renderPrimitiveRange(rsc, primIndex, 0, prim->mIndexBuffer->getType()->getDimX());
         return;
     }
 
-    renderPrimitiveRange(rsc, primIndex, 0, mVertexBuffers[0]->getType()->getDimX());
+    renderPrimitiveRange(rsc, primIndex, 0, mHal.state.vertexBuffers[0]->getType()->getDimX());
 }
 
 void Mesh::renderPrimitiveRange(Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const {
-    if (len < 1 || primIndex >= mPrimitivesCount || mAttribCount == 0) {
+    if (len < 1 || primIndex >= mHal.state.primitivesCount) {
         LOGE("Invalid mesh or parameters");
         return;
     }
 
-    rsc->checkError("Mesh::renderPrimitiveRange 1");
-    for (uint32_t ct=0; ct < mVertexBufferCount; ct++) {
-        mVertexBuffers[ct]->uploadCheck(rsc);
-    }
-    // update attributes with either buffer information or data ptr based on their current state
-    for (uint32_t ct=0; ct < mAttribCount; ct++) {
-        uint32_t allocIndex = mAttribAllocationIndex[ct];
-        Allocation *alloc = mVertexBuffers[allocIndex].get();
-        if (alloc->getIsBufferObject()) {
-            mAttribs[ct].buffer = alloc->getBufferObjectID();
-            mAttribs[ct].ptr = NULL;
-        } else {
-            mAttribs[ct].buffer = 0;
-            mAttribs[ct].ptr = (const uint8_t*)alloc->getPtr();
-        }
+    for (uint32_t ct=0; ct < mHal.state.vertexBuffersCount; ct++) {
+        mHal.state.vertexBuffers[ct]->uploadCheck(rsc);
     }
 
-    VertexArray va(mAttribs, mAttribCount);
-    va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
-
-    rsc->checkError("Mesh::renderPrimitiveRange 2");
-    Primitive_t *prim = mPrimitives[primIndex];
+    Primitive_t *prim = mHal.state.primitives[primIndex];
     if (prim->mIndexBuffer.get()) {
         prim->mIndexBuffer->uploadCheck(rsc);
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prim->mIndexBuffer->getBufferObjectID());
-        glDrawElements(prim->mGLPrimitive, len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2));
-    } else {
-        glDrawArrays(prim->mGLPrimitive, start, len);
     }
+    rsc->checkError("Mesh::renderPrimitiveRange upload check");
 
-    rsc->checkError("Mesh::renderPrimitiveRange");
+    mRSC->mHal.funcs.mesh.draw(mRSC, this, primIndex, start, len);
+    rsc->checkError("Mesh::renderPrimitiveRange draw");
 }
 
-
 void Mesh::uploadAll(Context *rsc) {
-    for (uint32_t ct = 0; ct < mVertexBufferCount; ct ++) {
-        if (mVertexBuffers[ct].get()) {
-            mVertexBuffers[ct]->deferredUploadToBufferObject(rsc);
+    for (uint32_t ct = 0; ct < mHal.state.vertexBuffersCount; ct ++) {
+        if (mHal.state.vertexBuffers[ct].get()) {
+            mHal.state.vertexBuffers[ct]->deferredUploadToBufferObject(rsc);
         }
     }
 
-    for (uint32_t ct = 0; ct < mPrimitivesCount; ct ++) {
-        if (mPrimitives[ct]->mIndexBuffer.get()) {
-            mPrimitives[ct]->mIndexBuffer->deferredUploadToBufferObject(rsc);
-        }
-    }
-}
-
-void Mesh::updateGLPrimitives() {
-    for (uint32_t i = 0; i < mPrimitivesCount; i ++) {
-        switch (mPrimitives[i]->mPrimitive) {
-            case RS_PRIMITIVE_POINT:          mPrimitives[i]->mGLPrimitive = GL_POINTS; break;
-            case RS_PRIMITIVE_LINE:           mPrimitives[i]->mGLPrimitive = GL_LINES; break;
-            case RS_PRIMITIVE_LINE_STRIP:     mPrimitives[i]->mGLPrimitive = GL_LINE_STRIP; break;
-            case RS_PRIMITIVE_TRIANGLE:       mPrimitives[i]->mGLPrimitive = GL_TRIANGLES; break;
-            case RS_PRIMITIVE_TRIANGLE_STRIP: mPrimitives[i]->mGLPrimitive = GL_TRIANGLE_STRIP; break;
-            case RS_PRIMITIVE_TRIANGLE_FAN:   mPrimitives[i]->mGLPrimitive = GL_TRIANGLE_FAN; break;
+    for (uint32_t ct = 0; ct < mHal.state.primitivesCount; ct ++) {
+        if (mHal.state.primitives[ct]->mIndexBuffer.get()) {
+            mHal.state.primitives[ct]->mIndexBuffer->deferredUploadToBufferObject(rsc);
         }
     }
 }
@@ -312,8 +225,8 @@
     uint32_t stride = 0;
     uint32_t numVerts = 0;
     // First we need to find the position ptr and stride
-    for (uint32_t ct=0; ct < mVertexBufferCount; ct++) {
-        const Type *bufferType = mVertexBuffers[ct]->getType();
+    for (uint32_t ct=0; ct < mHal.state.vertexBuffersCount; ct++) {
+        const Type *bufferType = mHal.state.vertexBuffers[ct]->getType();
         const Element *bufferElem = bufferType->getElement();
 
         for (uint32_t ct=0; ct < bufferElem->getFieldCount(); ct++) {
@@ -321,7 +234,7 @@
                 vectorSize = bufferElem->getField(ct)->getComponent().getVectorSize();
                 stride = bufferElem->getSizeBytes() / sizeof(float);
                 uint32_t offset = bufferElem->getFieldOffsetBytes(ct);
-                posPtr = (float*)((uint8_t*)mVertexBuffers[ct]->getPtr() + offset);
+                posPtr = (float*)((uint8_t*)mHal.state.vertexBuffers[ct]->getPtr() + offset);
                 numVerts = bufferType->getDimX();
                 break;
             }
@@ -353,73 +266,62 @@
 namespace renderscript {
 
 RsMesh rsi_MeshCreate(Context *rsc, uint32_t vtxCount, uint32_t idxCount) {
-    Mesh *sm = new Mesh(rsc);
+    Mesh *sm = new Mesh(rsc, vtxCount, idxCount);
     sm->incUserRef();
 
-    sm->mPrimitivesCount = idxCount;
-    sm->mPrimitives = new Mesh::Primitive_t *[sm->mPrimitivesCount];
-    for (uint32_t ct = 0; ct < idxCount; ct ++) {
-        sm->mPrimitives[ct] = new Mesh::Primitive_t;
-    }
-
-    sm->mVertexBufferCount = vtxCount;
-    sm->mVertexBuffers = new ObjectBaseRef<Allocation>[vtxCount];
-
     return sm;
 }
 
 void rsi_MeshBindVertex(Context *rsc, RsMesh mv, RsAllocation va, uint32_t slot) {
     Mesh *sm = static_cast<Mesh *>(mv);
-    rsAssert(slot < sm->mVertexBufferCount);
+    rsAssert(slot < sm->mHal.state.vertexBuffersCount);
 
-    sm->mVertexBuffers[slot].set((Allocation *)va);
+    sm->setVertexBuffer((Allocation *)va, slot);
 }
 
 void rsi_MeshBindIndex(Context *rsc, RsMesh mv, RsAllocation va, uint32_t primType, uint32_t slot) {
     Mesh *sm = static_cast<Mesh *>(mv);
-    rsAssert(slot < sm->mPrimitivesCount);
+    rsAssert(slot < sm->mHal.state.primitivesCount);
 
-    sm->mPrimitives[slot]->mIndexBuffer.set((Allocation *)va);
-    sm->mPrimitives[slot]->mPrimitive = (RsPrimitive)primType;
-    sm->updateGLPrimitives();
+    sm->setPrimitive((Allocation *)va, (RsPrimitive)primType, slot);
 }
 
 void rsi_MeshInitVertexAttribs(Context *rsc, RsMesh mv) {
     Mesh *sm = static_cast<Mesh *>(mv);
-    sm->initVertexAttribs();
+    sm->init();
 }
 
 }}
 
 void rsaMeshGetVertexBufferCount(RsContext con, RsMesh mv, int32_t *numVtx) {
     Mesh *sm = static_cast<Mesh *>(mv);
-    *numVtx = sm->mVertexBufferCount;
+    *numVtx = sm->mHal.state.vertexBuffersCount;
 }
 
 void rsaMeshGetIndexCount(RsContext con, RsMesh mv, int32_t *numIdx) {
     Mesh *sm = static_cast<Mesh *>(mv);
-    *numIdx = sm->mPrimitivesCount;
+    *numIdx = sm->mHal.state.primitivesCount;
 }
 
 void rsaMeshGetVertices(RsContext con, RsMesh mv, RsAllocation *vtxData, uint32_t vtxDataCount) {
     Mesh *sm = static_cast<Mesh *>(mv);
-    rsAssert(vtxDataCount == sm->mVertexBufferCount);
+    rsAssert(vtxDataCount == sm->mHal.state.vertexBuffersCount);
 
     for (uint32_t ct = 0; ct < vtxDataCount; ct ++) {
-        vtxData[ct] = sm->mVertexBuffers[ct].get();
-        sm->mVertexBuffers[ct]->incUserRef();
+        vtxData[ct] = sm->mHal.state.vertexBuffers[ct].get();
+        sm->mHal.state.vertexBuffers[ct]->incUserRef();
     }
 }
 
 void rsaMeshGetIndices(RsContext con, RsMesh mv, RsAllocation *va, uint32_t *primType, uint32_t idxDataCount) {
     Mesh *sm = static_cast<Mesh *>(mv);
-    rsAssert(idxDataCount == sm->mPrimitivesCount);
+    rsAssert(idxDataCount == sm->mHal.state.primitivesCount);
 
     for (uint32_t ct = 0; ct < idxDataCount; ct ++) {
-        va[ct] = sm->mPrimitives[ct]->mIndexBuffer.get();
-        primType[ct] = sm->mPrimitives[ct]->mPrimitive;
-        if (sm->mPrimitives[ct]->mIndexBuffer.get()) {
-            sm->mPrimitives[ct]->mIndexBuffer->incUserRef();
+        va[ct] = sm->mHal.state.primitives[ct]->mIndexBuffer.get();
+        primType[ct] = sm->mHal.state.primitives[ct]->mPrimitive;
+        if (sm->mHal.state.primitives[ct]->mIndexBuffer.get()) {
+            sm->mHal.state.primitives[ct]->mIndexBuffer->incUserRef();
         }
     }
 }
diff --git a/libs/rs/rsMesh.h b/libs/rs/rsMesh.h
index 3e080e2..1e279f4 100644
--- a/libs/rs/rsMesh.h
+++ b/libs/rs/rsMesh.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -29,57 +29,65 @@
 class Mesh : public ObjectBase {
 public:
     Mesh(Context *);
+    Mesh(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount);
     ~Mesh();
 
-    // Contains vertex data
-    // Position, normal, texcoord, etc could either be strided in one allocation
-    // of provided separetely in multiple ones
-    ObjectBaseRef<Allocation> *mVertexBuffers;
-    uint32_t mVertexBufferCount;
-
     // Either mIndexBuffer, mPrimitiveBuffer or both could have a NULL reference
     // If both are null, mPrimitive only would be used to render the mesh
-    struct Primitive_t
-    {
+    struct Primitive_t {
         ObjectBaseRef<Allocation> mIndexBuffer;
-
         RsPrimitive mPrimitive;
-        uint32_t mGLPrimitive;
     };
 
+    // compatibility to not break the build
+    ObjectBaseRef<Allocation> *mVertexBuffers;
+    uint32_t mVertexBufferCount;
     Primitive_t ** mPrimitives;
     uint32_t mPrimitivesCount;
+    // end compatibility
 
     virtual void serialize(OStream *stream) const;
     virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; }
     static Mesh *createFromStream(Context *rsc, IStream *stream);
+    void init();
 
-#ifndef ANDROID_RS_SERIALIZE
+    struct Hal {
+        mutable void *drv;
+
+        struct State {
+            // Contains vertex data
+            // Position, normal, texcoord, etc could either be strided in one allocation
+            // of provided separetely in multiple ones
+            ObjectBaseRef<Allocation> *vertexBuffers;
+            uint32_t vertexBuffersCount;
+
+            Primitive_t ** primitives;
+            uint32_t primitivesCount;
+        };
+        State state;
+    };
+    Hal mHal;
+
+    void setVertexBuffer(Allocation *vb, uint32_t index) {
+        mHal.state.vertexBuffers[index].set(vb);
+    }
+
+    void setPrimitive(Allocation *idx, RsPrimitive prim, uint32_t index) {
+        mHal.state.primitives[index]->mIndexBuffer.set(idx);
+        mHal.state.primitives[index]->mPrimitive = prim;
+    }
+
     void render(Context *) const;
     void renderPrimitive(Context *, uint32_t primIndex) const;
     void renderPrimitiveRange(Context *, uint32_t primIndex, uint32_t start, uint32_t len) const;
     void uploadAll(Context *);
-    void updateGLPrimitives();
-
-
 
     // Bounding volumes
     float mBBoxMin[3];
     float mBBoxMax[3];
     void computeBBox();
-
-    void initVertexAttribs();
-
 protected:
-    bool isValidGLComponent(const Element *elem, uint32_t fieldIdx);
-    // Attribues that allow us to map to GL
-    VertexArray::Attrib *mAttribs;
-    // This allows us to figure out which allocation the attribute
-    // belongs to. In the event the allocation is uploaded to GL
-    // buffer, it lets us properly map it
-    uint32_t *mAttribAllocationIndex;
-    uint32_t mAttribCount;
-#endif
+    bool mInitialized;
 };
 
 class MeshContext {
@@ -92,7 +100,7 @@
 
 }
 }
-#endif //ANDROID_RS_TRIANGLE_MESH_H
+#endif //ANDROID_RS_MESH_H
 
 
 
diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp
index 4ef05bf..b1d8f48 100644
--- a/libs/rs/rsProgram.cpp
+++ b/libs/rs/rsProgram.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -15,64 +15,47 @@
  */
 
 #include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#endif //ANDROID_RS_SERIALIZE
-
 #include "rsProgram.h"
 
 using namespace android;
 using namespace android::renderscript;
 
-Program::Program(Context *rsc) : ObjectBase(rsc) {
-   initMemberVars();
-}
-
 Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength,
                  const uint32_t * params, uint32_t paramLength)
-    : ObjectBase(rsc) {
+    : ProgramBase(rsc) {
 
     initMemberVars();
     for (uint32_t ct=0; ct < paramLength; ct+=2) {
         if (params[ct] == RS_PROGRAM_PARAM_INPUT) {
-            mInputCount++;
-        }
-        if (params[ct] == RS_PROGRAM_PARAM_OUTPUT) {
-            mOutputCount++;
+            mHal.state.inputElementsCount++;
         }
         if (params[ct] == RS_PROGRAM_PARAM_CONSTANT) {
-            mConstantCount++;
+            mHal.state.constantsCount++;
         }
         if (params[ct] == RS_PROGRAM_PARAM_TEXTURE_TYPE) {
-            mTextureCount++;
+            mHal.state.texturesCount++;
         }
     }
 
-    mTextures = new ObjectBaseRef<Allocation>[mTextureCount];
-    mSamplers = new ObjectBaseRef<Sampler>[mTextureCount];
-    mTextureTargets = new RsTextureTarget[mTextureCount];
-    mInputElements = new ObjectBaseRef<Element>[mInputCount];
-    mOutputElements = new ObjectBaseRef<Element>[mOutputCount];
-    mConstantTypes = new ObjectBaseRef<Type>[mConstantCount];
-    mConstants = new ObjectBaseRef<Allocation>[mConstantCount];
+    mHal.state.textures = new ObjectBaseRef<Allocation>[mHal.state.texturesCount];
+    mHal.state.samplers = new ObjectBaseRef<Sampler>[mHal.state.texturesCount];
+    mHal.state.textureTargets = new RsTextureTarget[mHal.state.texturesCount];
+    mHal.state.inputElements = new ObjectBaseRef<Element>[mHal.state.inputElementsCount];
+    mHal.state.constantTypes = new ObjectBaseRef<Type>[mHal.state.constantsCount];
+    mHal.state.constants = new ObjectBaseRef<Allocation>[mHal.state.constantsCount];
 
     uint32_t input = 0;
-    uint32_t output = 0;
     uint32_t constant = 0;
     uint32_t texture = 0;
     for (uint32_t ct=0; ct < paramLength; ct+=2) {
         if (params[ct] == RS_PROGRAM_PARAM_INPUT) {
-            mInputElements[input++].set(reinterpret_cast<Element *>(params[ct+1]));
-        }
-        if (params[ct] == RS_PROGRAM_PARAM_OUTPUT) {
-            mOutputElements[output++].set(reinterpret_cast<Element *>(params[ct+1]));
+            mHal.state.inputElements[input++].set(reinterpret_cast<Element *>(params[ct+1]));
         }
         if (params[ct] == RS_PROGRAM_PARAM_CONSTANT) {
-            mConstantTypes[constant++].set(reinterpret_cast<Type *>(params[ct+1]));
+            mHal.state.constantTypes[constant++].set(reinterpret_cast<Type *>(params[ct+1]));
         }
         if (params[ct] == RS_PROGRAM_PARAM_TEXTURE_TYPE) {
-            mTextureTargets[texture++] = (RsTextureTarget)params[ct+1];
+            mHal.state.textureTargets[texture++] = (RsTextureTarget)params[ct+1];
         }
     }
     mIsInternal = false;
@@ -84,88 +67,69 @@
         shaderLength -= internalTokenLen;
     }
     mUserShader.setTo(shaderText, shaderLength);
-
-    initAttribAndUniformArray();
 }
 
 Program::~Program() {
-    if (mRSC->props.mLogShaders) {
-        LOGV("Program::~Program with shader id %u", mShaderID);
-    }
 
-    if (mShaderID) {
-        glDeleteShader(mShaderID);
-    }
-
-    for (uint32_t ct=0; ct < mConstantCount; ct++) {
+    for (uint32_t ct=0; ct < mHal.state.constantsCount; ct++) {
         bindAllocation(NULL, NULL, ct);
     }
 
-    for (uint32_t ct=0; ct < mTextureCount; ct++) {
+    for (uint32_t ct=0; ct < mHal.state.texturesCount; ct++) {
         bindTexture(NULL, ct, NULL);
         bindSampler(NULL, ct, NULL);
     }
-    delete[] mTextures;
-    delete[] mSamplers;
-    delete[] mTextureTargets;
-    delete[] mInputElements;
-    delete[] mOutputElements;
-    delete[] mConstantTypes;
-    delete[] mConstants;
-    delete[] mAttribNames;
-    delete[] mUniformNames;
-    delete[] mUniformArraySizes;
-    mInputCount = 0;
-    mOutputCount = 0;
-    mConstantCount = 0;
+    delete[] mHal.state.textures;
+    delete[] mHal.state.samplers;
+    delete[] mHal.state.textureTargets;
+    delete[] mHal.state.inputElements;
+    delete[] mHal.state.constantTypes;
+    delete[] mHal.state.constants;
+    mHal.state.inputElementsCount = 0;
+    mHal.state.constantsCount = 0;
+    mHal.state.texturesCount = 0;
 }
 
 void Program::initMemberVars() {
     mDirty = true;
-    mShaderID = 0;
-    mAttribCount = 0;
-    mUniformCount = 0;
-    mTextureCount = 0;
 
-    mTextures = NULL;
-    mSamplers = NULL;
-    mTextureTargets = NULL;
-    mInputElements = NULL;
-    mOutputElements = NULL;
-    mConstantTypes = NULL;
-    mConstants = NULL;
-    mAttribNames = NULL;
-    mUniformNames = NULL;
-    mUniformArraySizes = NULL;
-    mInputCount = 0;
-    mOutputCount = 0;
-    mConstantCount = 0;
-    mIsValid = false;
+    mHal.drv = NULL;
+    mHal.state.textures = NULL;
+    mHal.state.samplers = NULL;
+    mHal.state.textureTargets = NULL;
+    mHal.state.inputElements = NULL;
+    mHal.state.constantTypes = NULL;
+    mHal.state.constants = NULL;
+
+    mHal.state.inputElementsCount = 0;
+    mHal.state.constantsCount = 0;
+    mHal.state.texturesCount = 0;
+
     mIsInternal = false;
 }
 
 void Program::bindAllocation(Context *rsc, Allocation *alloc, uint32_t slot) {
     if (alloc != NULL) {
-        if (slot >= mConstantCount) {
+        if (slot >= mHal.state.constantsCount) {
             LOGE("Attempt to bind alloc at slot %u, on shader id %u, but const count is %u",
-                 slot, (uint32_t)this, mConstantCount);
+                 slot, (uint32_t)this, mHal.state.constantsCount);
             rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind allocation");
             return;
         }
-        if (!alloc->getType()->isEqual(mConstantTypes[slot].get())) {
+        if (!alloc->getType()->isEqual(mHal.state.constantTypes[slot].get())) {
             LOGE("Attempt to bind alloc at slot %u, on shader id %u, but types mismatch",
                  slot, (uint32_t)this);
             rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind allocation");
             return;
         }
     }
-    if (mConstants[slot].get() == alloc) {
+    if (mHal.state.constants[slot].get() == alloc) {
         return;
     }
-    if (mConstants[slot].get()) {
-        mConstants[slot].get()->removeProgramToDirty(this);
+    if (mHal.state.constants[slot].get()) {
+        mHal.state.constants[slot].get()->removeProgramToDirty(this);
     }
-    mConstants[slot].set(alloc);
+    mHal.state.constants[slot].set(alloc);
     if (alloc) {
         alloc->addProgramToDirty(this);
     }
@@ -173,327 +137,33 @@
 }
 
 void Program::bindTexture(Context *rsc, uint32_t slot, Allocation *a) {
-    if (slot >= mTextureCount) {
-        LOGE("Attempt to bind texture to slot %u but tex count is %u", slot, mTextureCount);
+    if (slot >= mHal.state.texturesCount) {
+        LOGE("Attempt to bind texture to slot %u but tex count is %u", slot, mHal.state.texturesCount);
         rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind texture");
         return;
     }
 
-    if (a && a->getType()->getDimFaces() && mTextureTargets[slot] != RS_TEXTURE_CUBE) {
+    if (a && a->getType()->getDimFaces() && mHal.state.textureTargets[slot] != RS_TEXTURE_CUBE) {
         LOGE("Attempt to bind cubemap to slot %u but 2d texture needed", slot);
         rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind cubemap to 2d texture slot");
         return;
     }
 
-    //LOGE("bindtex %i %p", slot, a);
-    mTextures[slot].set(a);
+    mHal.state.textures[slot].set(a);
     mDirty = true;
 }
 
 void Program::bindSampler(Context *rsc, uint32_t slot, Sampler *s) {
-    if (slot >= mTextureCount) {
-        LOGE("Attempt to bind sampler to slot %u but tex count is %u", slot, mTextureCount);
+    if (slot >= mHal.state.texturesCount) {
+        LOGE("Attempt to bind sampler to slot %u but tex count is %u", slot, mHal.state.texturesCount);
         rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind sampler");
         return;
     }
 
-    mSamplers[slot].set(s);
+    mHal.state.samplers[slot].set(s);
     mDirty = true;
 }
 
-String8 Program::getGLSLInputString() const {
-    String8 s;
-    for (uint32_t ct=0; ct < mInputCount; ct++) {
-        const Element *e = mInputElements[ct].get();
-        for (uint32_t field=0; field < e->getFieldCount(); field++) {
-            const Element *f = e->getField(field);
-
-            // Cannot be complex
-            rsAssert(!f->getFieldCount());
-            switch (f->getComponent().getVectorSize()) {
-            case 1: s.append("attribute float ATTRIB_"); break;
-            case 2: s.append("attribute vec2 ATTRIB_"); break;
-            case 3: s.append("attribute vec3 ATTRIB_"); break;
-            case 4: s.append("attribute vec4 ATTRIB_"); break;
-            default:
-                rsAssert(0);
-            }
-
-            s.append(e->getFieldName(field));
-            s.append(";\n");
-        }
-    }
-    return s;
-}
-
-String8 Program::getGLSLOutputString() const {
-    return String8();
-}
-
-String8 Program::getGLSLConstantString() const {
-    return String8();
-}
-
-void Program::createShader() {
-}
-
-bool Program::loadShader(Context *rsc, uint32_t type) {
-    mShaderID = glCreateShader(type);
-    rsAssert(mShaderID);
-
-    if (rsc->props.mLogShaders) {
-        LOGV("Loading shader type %x, ID %i", type, mShaderID);
-        LOGV("%s", mShader.string());
-    }
-
-    if (mShaderID) {
-        const char * ss = mShader.string();
-        glShaderSource(mShaderID, 1, &ss, NULL);
-        glCompileShader(mShaderID);
-
-        GLint compiled = 0;
-        glGetShaderiv(mShaderID, GL_COMPILE_STATUS, &compiled);
-        if (!compiled) {
-            GLint infoLen = 0;
-            glGetShaderiv(mShaderID, GL_INFO_LOG_LENGTH, &infoLen);
-            if (infoLen) {
-                char* buf = (char*) malloc(infoLen);
-                if (buf) {
-                    glGetShaderInfoLog(mShaderID, infoLen, NULL, buf);
-                    LOGE("Could not compile shader \n%s\n", buf);
-                    free(buf);
-                }
-                glDeleteShader(mShaderID);
-                mShaderID = 0;
-                rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,");
-                return false;
-            }
-        }
-    }
-
-    if (rsc->props.mLogShaders) {
-        LOGV("--Shader load result %x ", glGetError());
-    }
-    mIsValid = true;
-    return true;
-}
-
-void Program::setShader(const char *txt, uint32_t len) {
-    mUserShader.setTo(txt, len);
-}
-
-void Program::appendUserConstants() {
-    for (uint32_t ct=0; ct < mConstantCount; ct++) {
-        const Element *e = mConstantTypes[ct]->getElement();
-        for (uint32_t field=0; field < e->getFieldCount(); field++) {
-            const Element *f = e->getField(field);
-            const char *fn = e->getFieldName(field);
-
-            if (fn[0] == '#') {
-                continue;
-            }
-
-            // Cannot be complex
-            rsAssert(!f->getFieldCount());
-            if (f->getType() == RS_TYPE_MATRIX_4X4) {
-                mShader.append("uniform mat4 UNI_");
-            } else if (f->getType() == RS_TYPE_MATRIX_3X3) {
-                mShader.append("uniform mat3 UNI_");
-            } else if (f->getType() == RS_TYPE_MATRIX_2X2) {
-                mShader.append("uniform mat2 UNI_");
-            } else {
-                switch (f->getComponent().getVectorSize()) {
-                case 1: mShader.append("uniform float UNI_"); break;
-                case 2: mShader.append("uniform vec2 UNI_"); break;
-                case 3: mShader.append("uniform vec3 UNI_"); break;
-                case 4: mShader.append("uniform vec4 UNI_"); break;
-                default:
-                    rsAssert(0);
-                }
-            }
-
-            mShader.append(fn);
-            if (e->getFieldArraySize(field) > 1) {
-                mShader.appendFormat("[%d]", e->getFieldArraySize(field));
-            }
-            mShader.append(";\n");
-        }
-    }
-}
-
-void Program::logUniform(const Element *field, const float *fd, uint32_t arraySize ) {
-    RsDataType dataType = field->getType();
-    uint32_t elementSize = field->getSizeBytes() / sizeof(float);
-    for (uint32_t i = 0; i < arraySize; i ++) {
-        if (arraySize > 1) {
-            LOGV("Array Element [%u]", i);
-        }
-        if (dataType == RS_TYPE_MATRIX_4X4) {
-            LOGV("Matrix4x4");
-            LOGV("{%f, %f, %f, %f",  fd[0], fd[4], fd[8], fd[12]);
-            LOGV(" %f, %f, %f, %f",  fd[1], fd[5], fd[9], fd[13]);
-            LOGV(" %f, %f, %f, %f",  fd[2], fd[6], fd[10], fd[14]);
-            LOGV(" %f, %f, %f, %f}", fd[3], fd[7], fd[11], fd[15]);
-        } else if (dataType == RS_TYPE_MATRIX_3X3) {
-            LOGV("Matrix3x3");
-            LOGV("{%f, %f, %f",  fd[0], fd[3], fd[6]);
-            LOGV(" %f, %f, %f",  fd[1], fd[4], fd[7]);
-            LOGV(" %f, %f, %f}", fd[2], fd[5], fd[8]);
-        } else if (dataType == RS_TYPE_MATRIX_2X2) {
-            LOGV("Matrix2x2");
-            LOGV("{%f, %f",  fd[0], fd[2]);
-            LOGV(" %f, %f}", fd[1], fd[3]);
-        } else {
-            switch (field->getComponent().getVectorSize()) {
-            case 1:
-                LOGV("Uniform 1 = %f", fd[0]);
-                break;
-            case 2:
-                LOGV("Uniform 2 = %f %f", fd[0], fd[1]);
-                break;
-            case 3:
-                LOGV("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]);
-                break;
-            case 4:
-                LOGV("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]);
-                break;
-            default:
-                rsAssert(0);
-            }
-        }
-        LOGE("Element size %u data=%p", elementSize, fd);
-        fd += elementSize;
-        LOGE("New data=%p", fd);
-    }
-}
-
-void Program::setUniform(Context *rsc, const Element *field, const float *fd,
-                         int32_t slot, uint32_t arraySize ) {
-    RsDataType dataType = field->getType();
-    if (dataType == RS_TYPE_MATRIX_4X4) {
-        glUniformMatrix4fv(slot, arraySize, GL_FALSE, fd);
-    } else if (dataType == RS_TYPE_MATRIX_3X3) {
-        glUniformMatrix3fv(slot, arraySize, GL_FALSE, fd);
-    } else if (dataType == RS_TYPE_MATRIX_2X2) {
-        glUniformMatrix2fv(slot, arraySize, GL_FALSE, fd);
-    } else {
-        switch (field->getComponent().getVectorSize()) {
-        case 1:
-            glUniform1fv(slot, arraySize, fd);
-            break;
-        case 2:
-            glUniform2fv(slot, arraySize, fd);
-            break;
-        case 3:
-            glUniform3fv(slot, arraySize, fd);
-            break;
-        case 4:
-            glUniform4fv(slot, arraySize, fd);
-            break;
-        default:
-            rsAssert(0);
-        }
-    }
-}
-
-void Program::setupUserConstants(Context *rsc, ShaderCache *sc, bool isFragment) {
-    uint32_t uidx = 0;
-    for (uint32_t ct=0; ct < mConstantCount; ct++) {
-        Allocation *alloc = mConstants[ct].get();
-        if (!alloc) {
-            LOGE("Attempting to set constants on shader id %u, but alloc at slot %u is not set", (uint32_t)this, ct);
-            rsc->setError(RS_ERROR_BAD_SHADER, "No constant allocation bound");
-            continue;
-        }
-
-        const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr());
-        const Element *e = mConstantTypes[ct]->getElement();
-        for (uint32_t field=0; field < e->getFieldCount(); field++) {
-            const Element *f = e->getField(field);
-            const char *fieldName = e->getFieldName(field);
-            // If this field is padding, skip it
-            if (fieldName[0] == '#') {
-                continue;
-            }
-
-            uint32_t offset = e->getFieldOffsetBytes(field);
-            const float *fd = reinterpret_cast<const float *>(&data[offset]);
-
-            int32_t slot = -1;
-            uint32_t arraySize = 1;
-            if (!isFragment) {
-                slot = sc->vtxUniformSlot(uidx);
-                arraySize = sc->vtxUniformSize(uidx);
-            } else {
-                slot = sc->fragUniformSlot(uidx);
-                arraySize = sc->fragUniformSize(uidx);
-            }
-            if (rsc->props.mLogShadersUniforms) {
-                LOGV("Uniform  slot=%i, offset=%i, constant=%i, field=%i, uidx=%i, name=%s", slot, offset, ct, field, uidx, fieldName);
-            }
-            uidx ++;
-            if (slot < 0) {
-                continue;
-            }
-
-            if (rsc->props.mLogShadersUniforms) {
-                logUniform(f, fd, arraySize);
-            }
-            setUniform(rsc, f, fd, slot, arraySize);
-        }
-    }
-}
-
-void Program::initAttribAndUniformArray() {
-    mAttribCount = 0;
-    for (uint32_t ct=0; ct < mInputCount; ct++) {
-        const Element *elem = mInputElements[ct].get();
-        for (uint32_t field=0; field < elem->getFieldCount(); field++) {
-            if (elem->getFieldName(field)[0] != '#') {
-                mAttribCount ++;
-            }
-        }
-    }
-
-    mUniformCount = 0;
-    for (uint32_t ct=0; ct < mConstantCount; ct++) {
-        const Element *elem = mConstantTypes[ct]->getElement();
-
-        for (uint32_t field=0; field < elem->getFieldCount(); field++) {
-            if (elem->getFieldName(field)[0] != '#') {
-                mUniformCount ++;
-            }
-        }
-    }
-    mUniformCount += mTextureCount;
-
-    if (mAttribCount) {
-        mAttribNames = new String8[mAttribCount];
-    }
-    if (mUniformCount) {
-        mUniformNames = new String8[mUniformCount];
-        mUniformArraySizes = new uint32_t[mUniformCount];
-    }
-}
-
-void Program::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix) {
-    rsAssert(e->getFieldCount());
-    for (uint32_t ct=0; ct < e->getFieldCount(); ct++) {
-        const Element *ce = e->getField(ct);
-        if (ce->getFieldCount()) {
-            initAddUserElement(ce, names, arrayLengths, count, prefix);
-        } else if (e->getFieldName(ct)[0] != '#') {
-            String8 tmp(prefix);
-            tmp.append(e->getFieldName(ct));
-            names[*count].setTo(tmp.string());
-            if (arrayLengths) {
-                arrayLengths[*count] = e->getFieldArraySize(ct);
-            }
-            (*count)++;
-        }
-    }
-}
-
 namespace android {
 namespace renderscript {
 
diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h
index c48464d..948ba3e 100644
--- a/libs/rs/rsProgram.h
+++ b/libs/rs/rsProgram.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -17,101 +17,68 @@
 #ifndef ANDROID_RS_PROGRAM_H
 #define ANDROID_RS_PROGRAM_H
 
-#include "rsObjectBase.h"
+#include "rsProgramBase.h"
 #include "rsElement.h"
 
 // ---------------------------------------------------------------------------
 namespace android {
 namespace renderscript {
-class ShaderCache;
 
 #define RS_SHADER_INTERNAL "//rs_shader_internal\n"
 #define RS_SHADER_ATTR "ATTRIB_"
 #define RS_SHADER_UNI "UNI_"
 
-class Program : public ObjectBase {
+class Program : public ProgramBase {
 public:
 
-    Program(Context *);
     Program(Context *, const char * shaderText, uint32_t shaderLength,
                        const uint32_t * params, uint32_t paramLength);
     virtual ~Program();
 
     void bindAllocation(Context *, Allocation *, uint32_t slot);
-    virtual void createShader();
 
     bool isUserProgram() const {return !mIsInternal;}
 
     void bindTexture(Context *, uint32_t slot, Allocation *);
     void bindSampler(Context *, uint32_t slot, Sampler *);
 
-    uint32_t getShaderID() const {return mShaderID;}
-    void setShader(const char *, uint32_t len);
+    struct Hal {
+        mutable void *drv;
 
-    uint32_t getAttribCount() const {return mAttribCount;}
-    uint32_t getUniformCount() const {return mUniformCount;}
-    const String8 & getAttribName(uint32_t i) const {return mAttribNames[i];}
-    const String8 & getUniformName(uint32_t i) const {return mUniformNames[i];}
-    uint32_t getUniformArraySize(uint32_t i) const {return mUniformArraySizes[i];}
+        struct State {
+            // The difference between Textures and Constants is how they are accessed
+            // Texture lookups go though a sampler which in effect converts normalized
+            // coordinates into type specific.  Multiple samples may also be taken
+            // and filtered.
+            //
+            // Constants are strictly accessed by the shader code
+            ObjectBaseRef<Allocation> *textures;
+            RsTextureTarget *textureTargets;
+            uint32_t texturesCount;
 
-    String8 getGLSLInputString() const;
-    String8 getGLSLOutputString() const;
-    String8 getGLSLConstantString() const;
+            ObjectBaseRef<Sampler> *samplers;
+            uint32_t samplersCount;
 
-    bool isValid() const {return mIsValid;}
-    void forceDirty() const {mDirty = true;}
+            ObjectBaseRef<Allocation> *constants;
+            ObjectBaseRef<Type> *constantTypes;
+            uint32_t constantsCount;
+
+            ObjectBaseRef<Element> *inputElements;
+            uint32_t inputElementsCount;
+        };
+        State state;
+    };
+    Hal mHal;
 
 protected:
-    // Components not listed in "in" will be passed though
-    // unless overwritten by components in out.
-    ObjectBaseRef<Element> *mInputElements;
-    ObjectBaseRef<Element> *mOutputElements;
-    ObjectBaseRef<Type> *mConstantTypes;
-    ObjectBaseRef<Allocation> *mConstants;
-    uint32_t mInputCount;
-    uint32_t mOutputCount;
-    uint32_t mConstantCount;
-    bool mIsValid;
     bool mIsInternal;
-
-    // Applies to vertex and fragment shaders only
-    void appendUserConstants();
-    void setupUserConstants(Context *rsc, ShaderCache *sc, bool isFragment);
-    void initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix);
-
-    void initAttribAndUniformArray();
-
-    mutable bool mDirty;
-    String8 mShader;
     String8 mUserShader;
-    uint32_t mShaderID;
-
-    uint32_t mTextureCount;
-    uint32_t mAttribCount;
-    uint32_t mUniformCount;
-    String8 *mAttribNames;
-    String8 *mUniformNames;
-    uint32_t *mUniformArraySizes;
-
-    void logUniform(const Element *field, const float *fd, uint32_t arraySize );
-    void setUniform(Context *rsc, const Element *field, const float *fd, int32_t slot, uint32_t arraySize );
     void initMemberVars();
-
-    // The difference between Textures and Constants is how they are accessed
-    // Texture lookups go though a sampler which in effect converts normalized
-    // coordinates into type specific.  Multiple samples may also be taken
-    // and filtered.
-    //
-    // Constants are strictly accessed by programetic loads.
-    ObjectBaseRef<Allocation> *mTextures;
-    ObjectBaseRef<Sampler> *mSamplers;
-    RsTextureTarget *mTextureTargets;
-    bool loadShader(Context *, uint32_t type);
 };
 
 }
 }
-#endif
+#endif // ANDROID_RS_PROGRAM_H
 
 
 
diff --git a/libs/rs/rsProgramBase.h b/libs/rs/rsProgramBase.h
new file mode 100644
index 0000000..80da453
--- /dev/null
+++ b/libs/rs/rsProgramBase.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2011 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_PROGRAM_BASE_H
+#define ANDROID_RS_PROGRAM_BASE_H
+
+#include "rsObjectBase.h"
+#include "rsElement.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class ProgramBase : public ObjectBase {
+public:
+    ProgramBase(Context *rsc) : ObjectBase(rsc) {
+        mDirty = true;
+    }
+
+    void forceDirty() const {mDirty = true;}
+
+protected:
+    mutable bool mDirty;
+};
+
+}
+}
+#endif // ANDROID_RS_PROGRAM_BASE_H
+
+
+
diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp
index ff314b7..fcbfbc8 100644
--- a/libs/rs/rsProgramFragment.cpp
+++ b/libs/rs/rsProgramFragment.cpp
@@ -15,13 +15,6 @@
  */
 
 #include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#endif //ANDROID_RS_SERIALIZE
-
 #include "rsProgramFragment.h"
 
 using namespace android;
@@ -31,19 +24,16 @@
                                  uint32_t shaderLength, const uint32_t * params,
                                  uint32_t paramLength)
     : Program(rsc, shaderText, shaderLength, params, paramLength) {
-
     mConstantColor[0] = 1.f;
     mConstantColor[1] = 1.f;
     mConstantColor[2] = 1.f;
     mConstantColor[3] = 1.f;
 
-    init(rsc);
+    mRSC->mHal.funcs.fragment.init(mRSC, this, mUserShader.string(), mUserShader.length());
 }
 
 ProgramFragment::~ProgramFragment() {
-    if (mShaderID) {
-        mRSC->mShaderCache.cleanupFragment(mShaderID);
-    }
+    mRSC->mHal.funcs.fragment.destroy(mRSC, this);
 }
 
 void ProgramFragment::setConstantColor(Context *rsc, float r, float g, float b, float a) {
@@ -52,7 +42,7 @@
         rsc->setError(RS_ERROR_BAD_SHADER, "Cannot  set fixed function emulation color on user program");
         return;
     }
-    if (mConstants[0].get() == NULL) {
+    if (mHal.state.constants[0].get() == NULL) {
         LOGE("Unable to set fixed function emulation color because allocation is missing");
         rsc->setError(RS_ERROR_BAD_SHADER, "Unable to set fixed function emulation color because allocation is missing");
         return;
@@ -61,12 +51,11 @@
     mConstantColor[1] = g;
     mConstantColor[2] = b;
     mConstantColor[3] = a;
-    memcpy(mConstants[0]->getPtr(), mConstantColor, 4*sizeof(float));
+    memcpy(mHal.state.constants[0]->getPtr(), mConstantColor, 4*sizeof(float));
     mDirty = true;
 }
 
-void ProgramFragment::setupGL2(Context *rsc, ProgramFragmentState *state, ShaderCache *sc) {
-    //LOGE("sgl2 frag1 %x", glGetError());
+void ProgramFragment::setupGL2(Context *rsc, ProgramFragmentState *state) {
     if ((state->mLast.get() == this) && !mDirty) {
         return;
     }
@@ -74,94 +63,16 @@
 
     rsc->checkError("ProgramFragment::setupGL2 start");
 
-    rsc->checkError("ProgramFragment::setupGL2 begin uniforms");
-    setupUserConstants(rsc, sc, true);
-
-    uint32_t numTexturesToBind = mTextureCount;
-    uint32_t numTexturesAvailable = rsc->getMaxFragmentTextures();
-    if (numTexturesToBind >= numTexturesAvailable) {
-        LOGE("Attempting to bind %u textures on shader id %u, but only %u are available",
-             mTextureCount, (uint32_t)this, numTexturesAvailable);
-        rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind more textuers than available");
-        numTexturesToBind = numTexturesAvailable;
-    }
-
-    for (uint32_t ct=0; ct < numTexturesToBind; ct++) {
-        glActiveTexture(GL_TEXTURE0 + ct);
-        if (!mTextures[ct].get()) {
+    for (uint32_t ct=0; ct < mHal.state.texturesCount; ct++) {
+        if (!mHal.state.textures[ct].get()) {
             LOGE("No texture bound for shader id %u, texture unit %u", (uint)this, ct);
             rsc->setError(RS_ERROR_BAD_SHADER, "No texture bound");
             continue;
         }
-
-        mTextures[ct]->uploadCheck(rsc);
-        GLenum target = (GLenum)mTextures[ct]->getGLTarget();
-        if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) {
-            LOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", (uint)this, ct);
-            rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader");
-        }
-        glBindTexture(target, mTextures[ct]->getTextureID());
-        rsc->checkError("ProgramFragment::setupGL2 tex bind");
-        if (mSamplers[ct].get()) {
-            mSamplers[ct]->setupGL(rsc, mTextures[ct].get());
-        } else {
-            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-            glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-            glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-            glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-            rsc->checkError("ProgramFragment::setupGL2 tex env");
-        }
-
-        glUniform1i(sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct);
-        rsc->checkError("ProgramFragment::setupGL2 uniforms");
+        mHal.state.textures[ct]->uploadCheck(rsc);
     }
 
-    glActiveTexture(GL_TEXTURE0);
-    mDirty = false;
-    rsc->checkError("ProgramFragment::setupGL2");
-}
-
-void ProgramFragment::loadShader(Context *rsc) {
-    Program::loadShader(rsc, GL_FRAGMENT_SHADER);
-}
-
-void ProgramFragment::createShader() {
-    if (mUserShader.length() > 1) {
-        mShader.append("precision mediump float;\n");
-        appendUserConstants();
-        char buf[256];
-        for (uint32_t ct=0; ct < mTextureCount; ct++) {
-            if (mTextureTargets[ct] == RS_TEXTURE_2D) {
-                snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct);
-            } else {
-                snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct);
-            }
-            mShader.append(buf);
-        }
-        mShader.append(mUserShader);
-    } else {
-        LOGE("ProgramFragment::createShader cannot create program, shader code not defined");
-        rsAssert(0);
-    }
-}
-
-void ProgramFragment::init(Context *rsc) {
-    uint32_t uniformIndex = 0;
-    if (mUserShader.size() > 0) {
-        for (uint32_t ct=0; ct < mConstantCount; ct++) {
-            initAddUserElement(mConstantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformIndex, RS_SHADER_UNI);
-        }
-    }
-    mTextureUniformIndexStart = uniformIndex;
-    char buf[256];
-    for (uint32_t ct=0; ct < mTextureCount; ct++) {
-        snprintf(buf, sizeof(buf), "UNI_Tex%i", ct);
-        mUniformNames[uniformIndex].setTo(buf);
-        mUniformArraySizes[uniformIndex] = 1;
-        uniformIndex++;
-    }
-
-    createShader();
+    rsc->mHal.funcs.fragment.setActive(rsc, this);
 }
 
 void ProgramFragment::serialize(OStream *stream) const {
diff --git a/libs/rs/rsProgramFragment.h b/libs/rs/rsProgramFragment.h
index 3d28946..7520af0 100644
--- a/libs/rs/rsProgramFragment.h
+++ b/libs/rs/rsProgramFragment.h
@@ -32,11 +32,8 @@
                              uint32_t paramLength);
     virtual ~ProgramFragment();
 
-    virtual void setupGL2(Context *, ProgramFragmentState *, ShaderCache *sc);
+    virtual void setupGL2(Context *, ProgramFragmentState *);
 
-    virtual void createShader();
-    virtual void loadShader(Context *rsc);
-    virtual void init(Context *rsc);
     virtual void serialize(OStream *stream) const;
     virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_FRAGMENT; }
     static ProgramFragment *createFromStream(Context *rsc, IStream *stream);
diff --git a/libs/rs/rsProgramRaster.cpp b/libs/rs/rsProgramRaster.cpp
index 9617c4d..435561d 100644
--- a/libs/rs/rsProgramRaster.cpp
+++ b/libs/rs/rsProgramRaster.cpp
@@ -24,7 +24,7 @@
 ProgramRaster::ProgramRaster(Context *rsc, bool pointSmooth,
                              bool lineSmooth, bool pointSprite,
                              float lineWidth, RsCullMode cull)
-    : Program(rsc) {
+    : ProgramBase(rsc) {
 
     memset(&mHal, 0, sizeof(mHal));
 
diff --git a/libs/rs/rsProgramRaster.h b/libs/rs/rsProgramRaster.h
index 045a7c1..efdb948 100644
--- a/libs/rs/rsProgramRaster.h
+++ b/libs/rs/rsProgramRaster.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2009-2011 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.
@@ -17,7 +17,7 @@
 #ifndef ANDROID_RS_PROGRAM_RASTER_H
 #define ANDROID_RS_PROGRAM_RASTER_H
 
-#include "rsProgram.h"
+#include "rsProgramBase.h"
 
 // ---------------------------------------------------------------------------
 namespace android {
@@ -25,7 +25,7 @@
 
 class ProgramRasterState;
 
-class ProgramRaster : public Program {
+class ProgramRaster : public ProgramBase {
 public:
     ProgramRaster(Context *rsc,
                   bool pointSmooth,
diff --git a/libs/rs/rsProgramStore.cpp b/libs/rs/rsProgramStore.cpp
index 2ad65e9..8fe890b 100644
--- a/libs/rs/rsProgramStore.cpp
+++ b/libs/rs/rsProgramStore.cpp
@@ -25,7 +25,7 @@
                            bool colorMaskR, bool colorMaskG, bool colorMaskB, bool colorMaskA,
                            bool depthMask, bool ditherEnable,
                            RsBlendSrcFunc srcFunc, RsBlendDstFunc destFunc,
-                           RsDepthFunc depthFunc) : Program(rsc) {
+                           RsDepthFunc depthFunc) : ProgramBase(rsc) {
     memset(&mHal, 0, sizeof(mHal));
 
     mHal.state.ditherEnable = ditherEnable;
diff --git a/libs/rs/rsProgramStore.h b/libs/rs/rsProgramStore.h
index bfe276d..77b3881 100644
--- a/libs/rs/rsProgramStore.h
+++ b/libs/rs/rsProgramStore.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -17,7 +17,7 @@
 #ifndef ANDROID_RS_PROGRAM_FRAGMENT_STORE_H
 #define ANDROID_RS_PROGRAM_FRAGMENT_STORE_H
 
-#include "rsProgram.h"
+#include "rsProgramBase.h"
 #include "rsStream.h"
 
 // ---------------------------------------------------------------------------
@@ -26,7 +26,7 @@
 
 class ProgramStoreState;
 
-class ProgramStore : public Program {
+class ProgramStore : public ProgramBase {
 public:
     ProgramStore(Context *,
                  bool colorMaskR, bool colorMaskG, bool colorMaskB, bool colorMaskA,
@@ -62,8 +62,6 @@
             RsDepthFunc depthFunc;
         };
         State state;
-
-
     };
     Hal mHal;
 
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index e407d3a..b8b3c0b 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -15,13 +15,6 @@
  */
 
 #include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#endif //ANDROID_RS_SERIALIZE
-
 #include "rsProgramVertex.h"
 
 using namespace android;
@@ -32,70 +25,25 @@
                              uint32_t shaderLength, const uint32_t * params,
                              uint32_t paramLength)
     : Program(rsc, shaderText, shaderLength, params, paramLength) {
-    init(rsc);
+    mRSC->mHal.funcs.vertex.init(mRSC, this, mUserShader.string(), mUserShader.length());
 }
 
 ProgramVertex::~ProgramVertex() {
-    if (mShaderID) {
-        mRSC->mShaderCache.cleanupVertex(mShaderID);
-    }
+    mRSC->mHal.funcs.vertex.destroy(mRSC, this);
 }
 
-void ProgramVertex::loadShader(Context *rsc) {
-    Program::loadShader(rsc, GL_VERTEX_SHADER);
-}
-
-void ProgramVertex::createShader(Context *rsc) {
-    if (mUserShader.length() > 1) {
-
-        appendUserConstants();
-
-        for (uint32_t ct=0; ct < mInputCount; ct++) {
-            const Element *e = mInputElements[ct].get();
-            for (uint32_t field=0; field < e->getFieldCount(); field++) {
-                const Element *f = e->getField(field);
-                const char *fn = e->getFieldName(field);
-
-                if (fn[0] == '#') {
-                    continue;
-                }
-
-                // Cannot be complex
-                rsAssert(!f->getFieldCount());
-                switch (f->getComponent().getVectorSize()) {
-                case 1: mShader.append("attribute float ATTRIB_"); break;
-                case 2: mShader.append("attribute vec2 ATTRIB_"); break;
-                case 3: mShader.append("attribute vec3 ATTRIB_"); break;
-                case 4: mShader.append("attribute vec4 ATTRIB_"); break;
-                default:
-                    rsAssert(0);
-                }
-
-                mShader.append(fn);
-                mShader.append(";\n");
-            }
-        }
-        mShader.append(mUserShader);
-    } else {
-        rsc->setError(RS_ERROR_FATAL_UNKNOWN,
-                      "ProgramFragment::createShader cannot create program, shader code not defined");
-    }
-}
-
-void ProgramVertex::setupGL2(Context *rsc, ProgramVertexState *state, ShaderCache *sc) {
+void ProgramVertex::setupGL2(Context *rsc, ProgramVertexState *state) {
     if ((state->mLast.get() == this) && !mDirty) {
         return;
     }
 
-    rsc->checkError("ProgramVertex::setupGL2 start");
-
     if (!isUserProgram()) {
-        if (mConstants[0].get() == NULL) {
+        if (mHal.state.constants[0].get() == NULL) {
             rsc->setError(RS_ERROR_FATAL_UNKNOWN,
                           "Unable to set fixed function emulation matrices because allocation is missing");
             return;
         }
-        float *f = static_cast<float *>(mConstants[0]->getPtr());
+        float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
         Matrix4x4 mvp;
         mvp.load(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]);
         Matrix4x4 t;
@@ -106,11 +54,9 @@
         }
     }
 
-    rsc->checkError("ProgramVertex::setupGL2 begin uniforms");
-    setupUserConstants(rsc, sc, false);
-
     state->mLast.set(this);
-    rsc->checkError("ProgramVertex::setupGL2");
+
+    rsc->mHal.funcs.vertex.setActive(rsc, this);
 }
 
 void ProgramVertex::setProjectionMatrix(Context *rsc, const rsc_Matrix *m) const {
@@ -119,12 +65,12 @@
                       "Attempting to set fixed function emulation matrix projection on user program");
         return;
     }
-    if (mConstants[0].get() == NULL) {
+    if (mHal.state.constants[0].get() == NULL) {
         rsc->setError(RS_ERROR_FATAL_UNKNOWN,
                       "Unable to set fixed function emulation matrix projection because allocation is missing");
         return;
     }
-    float *f = static_cast<float *>(mConstants[0]->getPtr());
+    float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
     memcpy(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], m, sizeof(rsc_Matrix));
     mDirty = true;
 }
@@ -135,12 +81,12 @@
                       "Attempting to set fixed function emulation matrix modelview on user program");
         return;
     }
-    if (mConstants[0].get() == NULL) {
+    if (mHal.state.constants[0].get() == NULL) {
         rsc->setError(RS_ERROR_FATAL_UNKNOWN,
                       "Unable to set fixed function emulation matrix modelview because allocation is missing");
         return;
     }
-    float *f = static_cast<float *>(mConstants[0]->getPtr());
+    float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
     memcpy(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], m, sizeof(rsc_Matrix));
     mDirty = true;
 }
@@ -151,12 +97,12 @@
                       "Attempting to set fixed function emulation matrix texture on user program");
         return;
     }
-    if (mConstants[0].get() == NULL) {
+    if (mHal.state.constants[0].get() == NULL) {
         rsc->setError(RS_ERROR_FATAL_UNKNOWN,
                       "Unable to set fixed function emulation matrix texture because allocation is missing");
         return;
     }
-    float *f = static_cast<float *>(mConstants[0]->getPtr());
+    float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
     memcpy(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET], m, sizeof(rsc_Matrix));
     mDirty = true;
 }
@@ -167,12 +113,12 @@
                       "Attempting to get fixed function emulation matrix projection on user program");
         return;
     }
-    if (mConstants[0].get() == NULL) {
+    if (mHal.state.constants[0].get() == NULL) {
         rsc->setError(RS_ERROR_FATAL_UNKNOWN,
                       "Unable to get fixed function emulation matrix projection because allocation is missing");
         return;
     }
-    float *f = static_cast<float *>(mConstants[0]->getPtr());
+    float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
     memcpy(m, &f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], sizeof(rsc_Matrix));
 }
 
@@ -180,27 +126,13 @@
     if (isUserProgram()) {
         return;
     }
-    float *f = static_cast<float *>(mConstants[0]->getPtr());
+    float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
     Matrix4x4 mvp;
     mvp.loadMultiply((Matrix4x4 *)&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET],
                      (Matrix4x4 *)&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]);
     mvp.vectorMultiply(v4out, v3in);
 }
 
-void ProgramVertex::init(Context *rsc) {
-    uint32_t attribCount = 0;
-    uint32_t uniformCount = 0;
-    if (mUserShader.size() > 0) {
-        for (uint32_t ct=0; ct < mInputCount; ct++) {
-            initAddUserElement(mInputElements[ct].get(), mAttribNames, NULL, &attribCount, RS_SHADER_ATTR);
-        }
-        for (uint32_t ct=0; ct < mConstantCount; ct++) {
-            initAddUserElement(mConstantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI);
-        }
-    }
-    createShader(rsc);
-}
-
 void ProgramVertex::serialize(OStream *stream) const {
 }
 
diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h
index 2a5c863..04224a7 100644
--- a/libs/rs/rsProgramVertex.h
+++ b/libs/rs/rsProgramVertex.h
@@ -31,7 +31,7 @@
                   const uint32_t * params, uint32_t paramLength);
     virtual ~ProgramVertex();
 
-    virtual void setupGL2(Context *rsc, ProgramVertexState *state, ShaderCache *sc);
+    virtual void setupGL2(Context *rsc, ProgramVertexState *state);
 
     void setProjectionMatrix(Context *, const rsc_Matrix *) const;
     void getProjectionMatrix(Context *, rsc_Matrix *) const;
@@ -40,10 +40,6 @@
 
     void transformToScreen(Context *, float *v4out, const float *v3in) const;
 
-    virtual void createShader(Context *);
-    virtual void loadShader(Context *);
-    virtual void init(Context *);
-
     virtual void serialize(OStream *stream) const;
     virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_VERTEX; }
     static ProgramVertex *createFromStream(Context *rsc, IStream *stream);
diff --git a/libs/rs/rsSampler.cpp b/libs/rs/rsSampler.cpp
index db2383a..2a05d16 100644
--- a/libs/rs/rsSampler.cpp
+++ b/libs/rs/rsSampler.cpp
@@ -15,11 +15,6 @@
  */
 
 #include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-#endif //ANDROID_RS_SERIALIZE
-
 #include "rsSampler.h"
 
 
@@ -39,77 +34,18 @@
                  RsSamplerValue wrapT,
                  RsSamplerValue wrapR,
                  float aniso) : ObjectBase(rsc) {
-    mMagFilter = magFilter;
-    mMinFilter = minFilter;
-    mWrapS = wrapS;
-    mWrapT = wrapT;
-    mWrapR = wrapR;
-    mAniso = aniso;
+    mHal.state.magFilter = magFilter;
+    mHal.state.minFilter = minFilter;
+    mHal.state.wrapS = wrapS;
+    mHal.state.wrapT = wrapT;
+    mHal.state.wrapR = wrapR;
+    mHal.state.aniso = aniso;
+
+    mRSC->mHal.funcs.sampler.init(mRSC, this);
 }
 
 Sampler::~Sampler() {
-}
-
-void Sampler::setupGL(const Context *rsc, const Allocation *tex) {
-    GLenum trans[] = {
-        GL_NEAREST, //RS_SAMPLER_NEAREST,
-        GL_LINEAR, //RS_SAMPLER_LINEAR,
-        GL_LINEAR_MIPMAP_LINEAR, //RS_SAMPLER_LINEAR_MIP_LINEAR,
-        GL_REPEAT, //RS_SAMPLER_WRAP,
-        GL_CLAMP_TO_EDGE, //RS_SAMPLER_CLAMP
-        GL_LINEAR_MIPMAP_NEAREST, //RS_SAMPLER_LINEAR_MIP_NEAREST
-    };
-
-    GLenum transNP[] = {
-        GL_NEAREST, //RS_SAMPLER_NEAREST,
-        GL_LINEAR, //RS_SAMPLER_LINEAR,
-        GL_LINEAR, //RS_SAMPLER_LINEAR_MIP_LINEAR,
-        GL_CLAMP_TO_EDGE, //RS_SAMPLER_WRAP,
-        GL_CLAMP_TO_EDGE, //RS_SAMPLER_CLAMP
-        GL_LINEAR, //RS_SAMPLER_LINEAR_MIP_NEAREST,
-    };
-
-    // This tells us the correct texture type
-    GLenum target = (GLenum)tex->getGLTarget();
-
-    if (!rsc->ext_OES_texture_npot() && tex->getType()->getIsNp2()) {
-        if (tex->getHasGraphicsMipmaps() &&
-            (rsc->ext_GL_NV_texture_npot_2D_mipmap() || rsc->ext_GL_IMG_texture_npot())) {
-            if (rsc->ext_GL_NV_texture_npot_2D_mipmap()) {
-                glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]);
-            } else {
-                switch (trans[mMinFilter]) {
-                case GL_LINEAR_MIPMAP_LINEAR:
-                    glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
-                    break;
-                default:
-                    glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]);
-                    break;
-                }
-            }
-        } else {
-            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[mMinFilter]);
-        }
-        glTexParameteri(target, GL_TEXTURE_MAG_FILTER, transNP[mMagFilter]);
-        glTexParameteri(target, GL_TEXTURE_WRAP_S, transNP[mWrapS]);
-        glTexParameteri(target, GL_TEXTURE_WRAP_T, transNP[mWrapT]);
-    } else {
-        if (tex->getHasGraphicsMipmaps()) {
-            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]);
-        } else {
-            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[mMinFilter]);
-        }
-        glTexParameteri(target, GL_TEXTURE_MAG_FILTER, trans[mMagFilter]);
-        glTexParameteri(target, GL_TEXTURE_WRAP_S, trans[mWrapS]);
-        glTexParameteri(target, GL_TEXTURE_WRAP_T, trans[mWrapT]);
-    }
-
-    float anisoValue = rsMin(rsc->ext_texture_max_aniso(), mAniso);
-    if (rsc->ext_texture_max_aniso() > 1.0f) {
-        glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoValue);
-    }
-
-    rsc->checkError("Sampler::setupGL2 tex env");
+    mRSC->mHal.funcs.sampler.destroy(mRSC, this);
 }
 
 void Sampler::bindToContext(SamplerState *ss, uint32_t slot) {
@@ -135,66 +71,14 @@
 namespace android {
 namespace renderscript {
 
-
-void rsi_SamplerBegin(Context *rsc) {
-    SamplerState * ss = &rsc->mStateSampler;
-
-    ss->mMagFilter = RS_SAMPLER_LINEAR;
-    ss->mMinFilter = RS_SAMPLER_LINEAR;
-    ss->mWrapS = RS_SAMPLER_WRAP;
-    ss->mWrapT = RS_SAMPLER_WRAP;
-    ss->mWrapR = RS_SAMPLER_WRAP;
-    ss->mAniso = 1.0f;
-}
-
-void rsi_SamplerSet(Context *rsc, RsSamplerParam param, RsSamplerValue value) {
-    SamplerState * ss = &rsc->mStateSampler;
-
-    switch (param) {
-    case RS_SAMPLER_MAG_FILTER:
-        ss->mMagFilter = value;
-        break;
-    case RS_SAMPLER_MIN_FILTER:
-        ss->mMinFilter = value;
-        break;
-    case RS_SAMPLER_WRAP_S:
-        ss->mWrapS = value;
-        break;
-    case RS_SAMPLER_WRAP_T:
-        ss->mWrapT = value;
-        break;
-    case RS_SAMPLER_WRAP_R:
-        ss->mWrapR = value;
-        break;
-    default:
-        LOGE("Attempting to set invalid value on sampler");
-        break;
-    }
-}
-
-void rsi_SamplerSet2(Context *rsc, RsSamplerParam param, float value) {
-    SamplerState * ss = &rsc->mStateSampler;
-
-    switch (param) {
-    case RS_SAMPLER_ANISO:
-        ss->mAniso = value;
-        break;
-    default:
-        LOGE("Attempting to set invalid value on sampler");
-        break;
-    }
-}
-
-RsSampler rsi_SamplerCreate(Context *rsc) {
-    SamplerState * ss = &rsc->mStateSampler;
-
-    Sampler * s = new Sampler(rsc,
-                              ss->mMagFilter,
-                              ss->mMinFilter,
-                              ss->mWrapS,
-                              ss->mWrapT,
-                              ss->mWrapR,
-                              ss->mAniso);
+RsSampler rsi_SamplerCreate(Context * rsc,
+                            RsSamplerValue magFilter,
+                            RsSamplerValue minFilter,
+                            RsSamplerValue wrapS,
+                            RsSamplerValue wrapT,
+                            RsSamplerValue wrapR,
+                            float aniso) {
+    Sampler * s = new Sampler(rsc, magFilter, minFilter, wrapS, wrapT, wrapR, aniso);
     s->incUserRef();
     return s;
 }
diff --git a/libs/rs/rsSampler.h b/libs/rs/rsSampler.h
index 737bb8b0..90b6082 100644
--- a/libs/rs/rsSampler.h
+++ b/libs/rs/rsSampler.h
@@ -40,9 +40,6 @@
 
     virtual ~Sampler();
 
-    void bind(Allocation *);
-    void setupGL(const Context *, const Allocation *);
-
     void bindToContext(SamplerState *, uint32_t slot);
     void unbindFromContext(SamplerState *);
 
@@ -50,14 +47,22 @@
     virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_SAMPLER; }
     static Sampler *createFromStream(Context *rsc, IStream *stream);
 
-protected:
-    RsSamplerValue mMagFilter;
-    RsSamplerValue mMinFilter;
-    RsSamplerValue mWrapS;
-    RsSamplerValue mWrapT;
-    RsSamplerValue mWrapR;
-    float mAniso;
+    struct Hal {
+        mutable void *drv;
 
+        struct State {
+            RsSamplerValue magFilter;
+            RsSamplerValue minFilter;
+            RsSamplerValue wrapS;
+            RsSamplerValue wrapT;
+            RsSamplerValue wrapR;
+            float aniso;
+        };
+        State state;
+    };
+    Hal mHal;
+
+protected:
     int32_t mBoundSlot;
 
 private:
@@ -67,13 +72,6 @@
 
 class SamplerState {
 public:
-    RsSamplerValue mMagFilter;
-    RsSamplerValue mMinFilter;
-    RsSamplerValue mWrapS;
-    RsSamplerValue mWrapT;
-    RsSamplerValue mWrapR;
-    float mAniso;
-
     ObjectBaseRef<Sampler> mSamplers[RS_MAX_SAMPLER_SLOT];
 };
 
diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp
index 71f1312..ecda485 100644
--- a/libs/rs/rsScriptC_LibGL.cpp
+++ b/libs/rs/rsScriptC_LibGL.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -21,6 +21,9 @@
 #include "rsMatrix2x2.h"
 
 #include "utils/Timers.h"
+#include "driver/rsdVertexArray.h"
+#include "driver/rsdShaderCache.h"
+#include "driver/rsdCore.h"
 
 #define GL_GLEXT_PROTOTYPES
 
@@ -134,6 +137,11 @@
         return;
     }
 
+    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+    if (!dc->gl.shaderCache->setup(rsc)) {
+        return;
+    }
+
     //LOGE("Quad");
     //LOGE("%4.2f, %4.2f, %4.2f", x1, y1, z1);
     //LOGE("%4.2f, %4.2f, %4.2f", x2, y2, z2);
@@ -143,12 +151,12 @@
     float vtx[] = {x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4};
     const float tex[] = {u1,v1, u2,v2, u3,v3, u4,v4};
 
-    VertexArray::Attrib attribs[2];
+    RsdVertexArray::Attrib attribs[2];
     attribs[0].set(GL_FLOAT, 3, 12, false, (uint32_t)vtx, "ATTRIB_position");
     attribs[1].set(GL_FLOAT, 2, 8, false, (uint32_t)tex, "ATTRIB_texture0");
 
-    VertexArray va(attribs, 2);
-    va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
+    RsdVertexArray va(attribs, 2);
+    va.setupGL2(rsc);
 
     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 }
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
index 90ae039..086db33 100644
--- a/libs/rs/rsType.h
+++ b/libs/rs/rsType.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -18,7 +18,6 @@
 #define ANDROID_STRUCTURED_TYPE_H
 
 #include "rsElement.h"
-#include "rsVertexArray.h"
 
 // ---------------------------------------------------------------------------
 namespace android {
diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h
index 4283d4a..4cc2abf 100644
--- a/libs/rs/rs_hal.h
+++ b/libs/rs/rs_hal.h
@@ -30,8 +30,13 @@
 class Allocation;
 class Script;
 class ScriptC;
+class Program;
 class ProgramStore;
 class ProgramRaster;
+class ProgramVertex;
+class ProgramFragment;
+class Mesh;
+class Sampler;
 
 typedef void *(*RsHalSymbolLookupFunc)(void *usrptr, char const *symbolName);
 
@@ -98,6 +103,30 @@
         void (*destroy)(const Context *rsc, const ProgramRaster *ps);
     } raster;
 
+    struct {
+        bool (*init)(const Context *rsc, const ProgramVertex *pv,
+                     const char* shader, uint32_t shaderLen);
+        void (*setActive)(const Context *rsc, const ProgramVertex *pv);
+        void (*destroy)(const Context *rsc, const ProgramVertex *pv);
+    } vertex;
+
+    struct {
+        bool (*init)(const Context *rsc, const ProgramFragment *pf,
+                     const char* shader, uint32_t shaderLen);
+        void (*setActive)(const Context *rsc, const ProgramFragment *pf);
+        void (*destroy)(const Context *rsc, const ProgramFragment *pf);
+    } fragment;
+
+    struct {
+        bool (*init)(const Context *rsc, const Mesh *m);
+        void (*draw)(const Context *rsc, const Mesh *m, uint32_t primIndex, uint32_t start, uint32_t len);
+        void (*destroy)(const Context *rsc, const Mesh *m);
+    } mesh;
+
+    struct {
+        bool (*init)(const Context *rsc, const Sampler *m);
+        void (*destroy)(const Context *rsc, const Sampler *m);
+    } sampler;
 
 } RsdHalFunctions;
 
diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c
index 239795d..1d8b9b5 100644
--- a/libs/rs/rsg_generator.c
+++ b/libs/rs/rsg_generator.c
@@ -228,7 +228,7 @@
             fprintf(f, ");\n");
         } else {
             fprintf(f, "    ThreadIO *io = &((Context *)rsc)->mIO;\n");
-            fprintf(f, "    uint32_t size = sizeof(RS_CMD_%s);\n", api->name);
+            fprintf(f, "    const uint32_t size = sizeof(RS_CMD_%s);\n", api->name);
             if (hasInlineDataPointers(api)) {
                 fprintf(f, "    uint32_t dataSize = 0;\n");
                 for (ct2=0; ct2 < api->paramCount; ct2++) {
@@ -241,10 +241,15 @@
 
             //fprintf(f, "    LOGE(\"add command %s\\n\");\n", api->name);
             if (hasInlineDataPointers(api)) {
-                fprintf(f, "    RS_CMD_%s *cmd = static_cast<RS_CMD_%s *>(io->mToCore.reserve(dataSize + sizeof(RS_CMD_%s)));\n", api->name, api->name, api->name);
+                fprintf(f, "    RS_CMD_%s *cmd = NULL;\n", api->name);
+                fprintf(f, "    if (dataSize < 1024) {;\n");
+                fprintf(f, "        cmd = static_cast<RS_CMD_%s *>(io->mToCore.reserve(dataSize + size));\n", api->name);
+                fprintf(f, "    } else {\n");
+                fprintf(f, "        cmd = static_cast<RS_CMD_%s *>(io->mToCore.reserve(size));\n", api->name);
+                fprintf(f, "    }\n");
                 fprintf(f, "    uint8_t *payload = (uint8_t *)&cmd[1];\n");
             } else {
-                fprintf(f, "    RS_CMD_%s *cmd = static_cast<RS_CMD_%s *>(io->mToCore.reserve(sizeof(RS_CMD_%s)));\n", api->name, api->name, api->name);
+                fprintf(f, "    RS_CMD_%s *cmd = static_cast<RS_CMD_%s *>(io->mToCore.reserve(size));\n", api->name, api->name);
             }
 
             for (ct2=0; ct2 < api->paramCount; ct2++) {
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index dc223f9..4393504 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -47,16 +47,16 @@
 
 class NativeBuffer 
     : public EGLNativeBase<
-        android_native_buffer_t, 
+        ANativeWindowBuffer, 
         NativeBuffer, 
         LightRefBase<NativeBuffer> >
 {
 public:
     NativeBuffer(int w, int h, int f, int u) : BASE() {
-        android_native_buffer_t::width  = w;
-        android_native_buffer_t::height = h;
-        android_native_buffer_t::format = f;
-        android_native_buffer_t::usage  = u;
+        ANativeWindowBuffer::width  = w;
+        ANativeWindowBuffer::height = h;
+        ANativeWindowBuffer::format = f;
+        ANativeWindowBuffer::usage  = u;
     }
 private:
     friend class LightRefBase<NativeBuffer>;    
@@ -201,7 +201,7 @@
 }
 
 int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, 
-        android_native_buffer_t** buffer)
+        ANativeWindowBuffer** buffer)
 {
     FramebufferNativeWindow* self = getSelf(window);
     Mutex::Autolock _l(self->mutex);
@@ -229,7 +229,7 @@
 }
 
 int FramebufferNativeWindow::lockBuffer(ANativeWindow* window, 
-        android_native_buffer_t* buffer)
+        ANativeWindowBuffer* buffer)
 {
     FramebufferNativeWindow* self = getSelf(window);
     Mutex::Autolock _l(self->mutex);
@@ -249,7 +249,7 @@
 }
 
 int FramebufferNativeWindow::queueBuffer(ANativeWindow* window, 
-        android_native_buffer_t* buffer)
+        ANativeWindowBuffer* buffer)
 {
     FramebufferNativeWindow* self = getSelf(window);
     Mutex::Autolock _l(self->mutex);
@@ -270,10 +270,10 @@
     return res;
 }
 
-int FramebufferNativeWindow::query(ANativeWindow* window,
+int FramebufferNativeWindow::query(const ANativeWindow* window,
         int what, int* value) 
 {
-    FramebufferNativeWindow* self = getSelf(window);
+    const FramebufferNativeWindow* self = getSelf(window);
     Mutex::Autolock _l(self->mutex);
     framebuffer_device_t* fb = self->fbDev;
     switch (what) {
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 97312a6..54a3ffa 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -33,7 +33,7 @@
 namespace android {
 
 // ===========================================================================
-// Buffer and implementation of android_native_buffer_t
+// Buffer and implementation of ANativeWindowBuffer
 // ===========================================================================
 
 GraphicBuffer::GraphicBuffer()
@@ -77,7 +77,7 @@
     handle = inHandle;
 }
 
-GraphicBuffer::GraphicBuffer(android_native_buffer_t* buffer, bool keepOwnership)
+GraphicBuffer::GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership)
     : BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
       mBufferMapper(GraphicBufferMapper::get()),
       mInitCheck(NO_ERROR), mIndex(-1), mWrappedBuffer(buffer)
@@ -119,9 +119,9 @@
     GraphicBufferAllocator::dumpToSystemLog();
 }
 
-android_native_buffer_t* GraphicBuffer::getNativeBuffer() const
+ANativeWindowBuffer* GraphicBuffer::getNativeBuffer() const
 {
-    return static_cast<android_native_buffer_t*>(
+    return static_cast<ANativeWindowBuffer*>(
             const_cast<GraphicBuffer*>(this));
 }
 
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 60085b5..02d6b66 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -68,7 +68,21 @@
      * @param headers the headers to be sent together with the request for the data
      * @throws IllegalArgumentException If the URI is invalid.
      */
-    public native void setDataSource(String uri, Map<String, String> headers)
+    public void setDataSource(String uri,  Map<String, String> headers)
+            throws IllegalArgumentException {
+        int i = 0;
+        String[] keys = new String[headers.size()];
+        String[] values = new String[headers.size()];
+        for (Map.Entry<String, String> entry: headers.entrySet()) {
+            keys[i] = entry.getKey();
+            values[i] = entry.getValue();
+            ++i;
+        }
+        _setDataSource(uri, keys, values);
+    }
+
+    private native void _setDataSource(
+        String uri, String[] keys, String[] values)
         throws IllegalArgumentException;
 
     /**
@@ -432,5 +446,12 @@
      * This key retrieves the average bitrate (in bits/sec), if available.
      */
     public static final int METADATA_KEY_BITRATE         = 20;
+    /**
+     * This key retrieves the language code of text tracks, if available.
+     * If multiple text tracks present, the return value will look like:
+     * "eng:chi"
+     * @hide
+     */
+    public static final int METADATA_KEY_TIMED_TEXT_LANGUAGES      = 21;
     // Add more here...
 }
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index b914169..6c61297 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -799,8 +799,23 @@
      * @throws IllegalStateException if it is called in an invalid state
      * @hide pending API council
      */
-    public native void setDataSource(String path,  Map<String, String> headers)
-            throws IOException, IllegalArgumentException, IllegalStateException;
+    public void setDataSource(String path, Map<String, String> headers)
+            throws IOException, IllegalArgumentException, IllegalStateException
+    {
+        int i = 0;
+        String[] keys = new String[headers.size()];
+        String[] values = new String[headers.size()];
+        for (Map.Entry<String, String> entry: headers.entrySet()) {
+            keys[i] = entry.getKey();
+            values[i] = entry.getValue();
+            ++i;
+        }
+        _setDataSource(path, keys, values);
+    }
+
+    private native void _setDataSource(
+        String path, String[] keys, String[] values)
+        throws IOException, IllegalArgumentException, IllegalStateException;
 
     /**
      * Sets the data source (FileDescriptor) to use. It is the caller's responsibility
@@ -1227,6 +1242,15 @@
      */
     public native void attachAuxEffect(int effectId);
 
+    /* Do not change these values without updating their counterparts
+     * in include/media/mediaplayer.h!
+     */
+    /**
+     * Key used in setParameter method.
+     * Indicates the index of the timed text track to be enabled/disabled
+     */
+    private static final int KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX = 1000;
+
     /**
      * Sets the parameter indicated by key.
      * @param key key indicates the parameter to be set.
@@ -1360,6 +1384,36 @@
     private native final void native_finalize();
 
     /**
+     * @param index The index of the text track to be turned on.
+     * @return true if the text track is enabled successfully.
+     * {@hide}
+     */
+    public boolean enableTimedTextTrackIndex(int index) {
+        if (index < 0) {
+            return false;
+        }
+        return setParameter(KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX, index);
+    }
+
+    /**
+     * Enables the first timed text track if any.
+     * @return true if the text track is enabled successfully
+     * {@hide}
+     */
+    public boolean enableTimedText() {
+        return enableTimedTextTrackIndex(0);
+    }
+
+    /**
+     * Disables timed text display.
+     * @return true if the text track is disabled successfully.
+     * {@hide}
+     */
+    public boolean disableTimedText() {
+        return setParameter(KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX, -1);
+    }
+
+    /**
      * @param reply Parcel with audio/video duration info for battery
                     tracking usage
      * @return The status code.
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 80cc94e..790eaa3 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -431,34 +431,8 @@
             mFileSize = fileSize;
 
             if (!isDirectory) {
-                // special case certain file names
-                // I use regionMatches() instead of substring() below
-                // to avoid memory allocation
-                int lastSlash = path.lastIndexOf('/');
-                if (lastSlash >= 0 && lastSlash + 2 < path.length()) {
-                    if (!noMedia) {
-                        // ignore those ._* files created by MacOS
-                        if (path.regionMatches(lastSlash + 1, "._", 0, 2)) {
-                            noMedia = true;
-                        }
-
-                        // ignore album art files created by Windows Media Player:
-                        // Folder.jpg, AlbumArtSmall.jpg, AlbumArt_{...}_Large.jpg
-                        // and AlbumArt_{...}_Small.jpg
-                        if (path.regionMatches(true, path.length() - 4, ".jpg", 0, 4)) {
-                            if (path.regionMatches(true, lastSlash + 1, "AlbumArt_{", 0, 10) ||
-                                    path.regionMatches(true, lastSlash + 1, "AlbumArt.", 0, 9)) {
-                                noMedia = true;
-                            }
-                            int length = path.length() - lastSlash - 1;
-                            if ((length == 17 && path.regionMatches(
-                                    true, lastSlash + 1, "AlbumArtSmall", 0, 13)) ||
-                                    (length == 10
-                                     && path.regionMatches(true, lastSlash + 1, "Folder", 0, 6))) {
-                                noMedia = true;
-                            }
-                        }
-                    }
+                if (!noMedia && isNoMediaFile(path)) {
+                    noMedia = true;
                 }
                 mNoMedia = noMedia;
 
@@ -1231,6 +1205,40 @@
         }
     }
 
+    private static boolean isNoMediaFile(String path) {
+        File file = new File(path);
+        if (file.isDirectory()) return false;
+
+        // special case certain file names
+        // I use regionMatches() instead of substring() below
+        // to avoid memory allocation
+        int lastSlash = path.lastIndexOf('/');
+        if (lastSlash >= 0 && lastSlash + 2 < path.length()) {
+            // ignore those ._* files created by MacOS
+            if (path.regionMatches(lastSlash + 1, "._", 0, 2)) {
+                return true;
+            }
+
+            // ignore album art files created by Windows Media Player:
+            // Folder.jpg, AlbumArtSmall.jpg, AlbumArt_{...}_Large.jpg
+            // and AlbumArt_{...}_Small.jpg
+            if (path.regionMatches(true, path.length() - 4, ".jpg", 0, 4)) {
+                if (path.regionMatches(true, lastSlash + 1, "AlbumArt_{", 0, 10) ||
+                        path.regionMatches(true, lastSlash + 1, "AlbumArt.", 0, 9)) {
+                    return true;
+                }
+                int length = path.length() - lastSlash - 1;
+                if ((length == 17 && path.regionMatches(
+                        true, lastSlash + 1, "AlbumArtSmall", 0, 13)) ||
+                        (length == 10
+                         && path.regionMatches(true, lastSlash + 1, "Folder", 0, 6))) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     public static boolean isNoMediaPath(String path) {
         if (path == null) return false;
 
@@ -1252,7 +1260,7 @@
             }
             offset = slashIndex;
         }
-        return false;
+        return isNoMediaFile(path);
     }
 
     public void scanMtpFile(String path, String volumeName, int objectHandle, int format) {
diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
index 47bb8c9..3272fed 100644
--- a/media/java/android/mtp/MtpDevice.java
+++ b/media/java/android/mtp/MtpDevice.java
@@ -22,7 +22,10 @@
 import android.util.Log;
 
 /**
- * This class represents an MTP or PTP device connected on the USB host bus.
+ * This class represents an MTP or PTP device connected on the USB host bus. An application can
+ * instantiate an object of this type, by referencing an attached {@link
+ * android.hardware.usb.UsbDevice} and then use methods in this class to get information about the
+ * device and objects stored on it, as well as open the connection and transfer data.
  */
 public final class MtpDevice {
 
diff --git a/media/java/android/mtp/package.html b/media/java/android/mtp/package.html
new file mode 100644
index 0000000..6bd9229
--- /dev/null
+++ b/media/java/android/mtp/package.html
@@ -0,0 +1,8 @@
+<html>
+<body>
+<p>Provides APIs that let you interact directly with connected cameras and other devices, using the
+PTP (Picture Transfer Protocol) subset of the MTP (Media Transfer Protocol) specification. Your
+application can receive notifications when devices are attached and removed, manage files and
+storage on those devices, and transfer files and metadata from the devices.</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 77cedd5..d4b326c 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -9,6 +9,7 @@
     android_media_ResampleInputStream.cpp \
     android_media_MediaProfiles.cpp \
     android_media_AmrInputStream.cpp \
+    android_media_Utils.cpp \
     android_mtp_MtpDatabase.cpp \
     android_mtp_MtpDevice.cpp \
     android_mtp_MtpServer.cpp \
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 2ba9b3f..73aea2a 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -28,6 +28,7 @@
 #include "jni.h"
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
+#include "android_media_Utils.h"
 
 
 using namespace android;
@@ -79,7 +80,9 @@
 
 static void
 android_media_MediaMetadataRetriever_setDataSourceAndHeaders(
-        JNIEnv *env, jobject thiz, jstring path, jobject headers) {
+        JNIEnv *env, jobject thiz, jstring path,
+        jobjectArray keys, jobjectArray values) {
+
     LOGV("setDataSource");
     MediaMetadataRetriever* retriever = getRetriever(env, thiz);
     if (retriever == 0) {
@@ -103,7 +106,6 @@
     }
 
     String8 pathStr(tmp);
-
     env->ReleaseStringUTFChars(path, tmp);
     tmp = NULL;
 
@@ -114,119 +116,26 @@
         return;
     }
 
-    // headers is a Map<String, String>.
     // We build a similar KeyedVector out of it.
     KeyedVector<String8, String8> headersVector;
-    if (headers) {
-        // Get the Map's entry Set.
-        jclass mapClass = env->FindClass("java/util/Map");
-        if (mapClass == NULL) {
-            return;
-        }
-
-        jmethodID entrySet =
-            env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;");
-        if (entrySet == NULL) {
-            return;
-        }
-
-        jobject set = env->CallObjectMethod(headers, entrySet);
-        if (set == NULL) {
-            return;
-        }
-
-        // Obtain an iterator over the Set
-        jclass setClass = env->FindClass("java/util/Set");
-        if (setClass == NULL) {
-            return;
-        }
-
-        jmethodID iterator =
-            env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");
-        if (iterator == NULL) {
-            return;
-        }
-
-        jobject iter = env->CallObjectMethod(set, iterator);
-        if (iter == NULL) {
-            return;
-        }
-
-        // Get the Iterator method IDs
-        jclass iteratorClass = env->FindClass("java/util/Iterator");
-        if (iteratorClass == NULL) {
-            return;
-        }
-        jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z");
-        if (hasNext == NULL) {
-            return;
-        }
-
-        jmethodID next =
-            env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
-        if (next == NULL) {
-            return;
-        }
-
-        // Get the Entry class method IDs
-        jclass entryClass = env->FindClass("java/util/Map$Entry");
-        if (entryClass == NULL) {
-            return;
-        }
-
-        jmethodID getKey =
-            env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;");
-        if (getKey == NULL) {
-            return;
-        }
-
-        jmethodID getValue =
-            env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;");
-        if (getValue == NULL) {
-            return;
-        }
-
-        // Iterate over the entry Set
-        while (env->CallBooleanMethod(iter, hasNext)) {
-            jobject entry = env->CallObjectMethod(iter, next);
-            jstring key = (jstring) env->CallObjectMethod(entry, getKey);
-            jstring value = (jstring) env->CallObjectMethod(entry, getValue);
-
-            const char* keyStr = env->GetStringUTFChars(key, NULL);
-            if (!keyStr) {  // Out of memory
-                return;
-            }
-
-            const char* valueStr = env->GetStringUTFChars(value, NULL);
-            if (!valueStr) {  // Out of memory
-                env->ReleaseStringUTFChars(key, keyStr);
-                return;
-            }
-
-            headersVector.add(String8(keyStr), String8(valueStr));
-
-            env->DeleteLocalRef(entry);
-            env->ReleaseStringUTFChars(key, keyStr);
-            env->DeleteLocalRef(key);
-            env->ReleaseStringUTFChars(value, valueStr);
-            env->DeleteLocalRef(value);
-        }
-
+    if (!ConvertKeyValueArraysToKeyedVector(
+            env, keys, values, &headersVector)) {
+        return;
     }
-
     process_media_retriever_call(
             env,
             retriever->setDataSource(
-                pathStr.string(), headers ? &headersVector : NULL),
+                pathStr.string(), headersVector.size() > 0 ? &headersVector : NULL),
 
             "java/lang/RuntimeException",
             "setDataSource failed");
 }
 
+
 static void android_media_MediaMetadataRetriever_setDataSource(
         JNIEnv *env, jobject thiz, jstring path) {
     android_media_MediaMetadataRetriever_setDataSourceAndHeaders(
-            env, thiz, path, NULL);
+            env, thiz, path, NULL, NULL);
 }
 
 static void android_media_MediaMetadataRetriever_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
@@ -539,7 +448,13 @@
 // JNI mapping between Java methods and native methods
 static JNINativeMethod nativeMethods[] = {
         {"setDataSource",   "(Ljava/lang/String;)V", (void *)android_media_MediaMetadataRetriever_setDataSource},
-        {"setDataSource",   "(Ljava/lang/String;Ljava/util/Map;)V", (void *)android_media_MediaMetadataRetriever_setDataSourceAndHeaders},
+
+        {
+            "_setDataSource",
+            "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
+            (void *)android_media_MediaMetadataRetriever_setDataSourceAndHeaders
+        },
+
         {"setDataSource",   "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaMetadataRetriever_setDataSourceFD},
         {"_getFrameAtTime", "(JI)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtTime},
         {"extractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata},
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 8763ebd..b03aa38 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -33,6 +33,8 @@
 #include "utils/Errors.h"  // for status_t
 #include "utils/KeyedVector.h"
 #include "utils/String8.h"
+#include "android_media_Utils.h"
+
 #include "android_util_Binder.h"
 #include <binder/Parcel.h>
 #include <gui/SurfaceTexture.h>
@@ -186,7 +188,9 @@
 
 static void
 android_media_MediaPlayer_setDataSourceAndHeaders(
-        JNIEnv *env, jobject thiz, jstring path, jobject headers) {
+        JNIEnv *env, jobject thiz, jstring path,
+        jobjectArray keys, jobjectArray values) {
+
     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
     if (mp == NULL ) {
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
@@ -207,112 +211,18 @@
     env->ReleaseStringUTFChars(path, tmp);
     tmp = NULL;
 
-    // headers is a Map<String, String>.
-    // We build a similar KeyedVector out of it.
+    // We build a KeyedVector out of the key and val arrays
     KeyedVector<String8, String8> headersVector;
-    if (headers) {
-        // Get the Map's entry Set.
-        jclass mapClass = env->FindClass("java/util/Map");
-        if (mapClass == NULL) {
-            return;
-        }
-
-        jmethodID entrySet =
-            env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;");
-        if (entrySet == NULL) {
-            return;
-        }
-
-        jobject set = env->CallObjectMethod(headers, entrySet);
-        if (set == NULL) {
-            return;
-        }
-
-        // Obtain an iterator over the Set
-        jclass setClass = env->FindClass("java/util/Set");
-        if (setClass == NULL) {
-            return;
-        }
-
-        jmethodID iterator =
-            env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");
-        if (iterator == NULL) {
-            return;
-        }
-
-        jobject iter = env->CallObjectMethod(set, iterator);
-        if (iter == NULL) {
-            return;
-        }
-
-        // Get the Iterator method IDs
-        jclass iteratorClass = env->FindClass("java/util/Iterator");
-        if (iteratorClass == NULL) {
-            return;
-        }
-
-        jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z");
-        if (hasNext == NULL) {
-            return;
-        }
-
-        jmethodID next =
-            env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
-        if (next == NULL) {
-            return;
-        }
-
-        // Get the Entry class method IDs
-        jclass entryClass = env->FindClass("java/util/Map$Entry");
-        if (entryClass == NULL) {
-            return;
-        }
-
-        jmethodID getKey =
-            env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;");
-        if (getKey == NULL) {
-            return;
-        }
-
-        jmethodID getValue =
-            env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;");
-        if (getValue == NULL) {
-            return;
-        }
-
-        // Iterate over the entry Set
-        while (env->CallBooleanMethod(iter, hasNext)) {
-            jobject entry = env->CallObjectMethod(iter, next);
-            jstring key = (jstring) env->CallObjectMethod(entry, getKey);
-            jstring value = (jstring) env->CallObjectMethod(entry, getValue);
-
-            const char* keyStr = env->GetStringUTFChars(key, NULL);
-            if (!keyStr) {  // Out of memory
-                return;
-            }
-
-            const char* valueStr = env->GetStringUTFChars(value, NULL);
-            if (!valueStr) {  // Out of memory
-                env->ReleaseStringUTFChars(key, keyStr);
-                return;
-            }
-
-            headersVector.add(String8(keyStr), String8(valueStr));
-
-            env->DeleteLocalRef(entry);
-            env->ReleaseStringUTFChars(key, keyStr);
-            env->DeleteLocalRef(key);
-            env->ReleaseStringUTFChars(value, valueStr);
-            env->DeleteLocalRef(value);
-        }
-
+    if (!ConvertKeyValueArraysToKeyedVector(
+            env, keys, values, &headersVector)) {
+        return;
     }
 
     LOGV("setDataSource: path %s", pathStr);
     status_t opStatus =
         mp->setDataSource(
                 pathStr,
-                headers ? &headersVector : NULL);
+                headersVector.size() > 0? &headersVector : NULL);
 
     process_media_player_call(
             env, thiz, opStatus, "java/io/IOException",
@@ -322,7 +232,7 @@
 static void
 android_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstring path)
 {
-    android_media_MediaPlayer_setDataSourceAndHeaders(env, thiz, path, 0);
+    android_media_MediaPlayer_setDataSourceAndHeaders(env, thiz, path, NULL, NULL);
 }
 
 static void
@@ -851,7 +761,13 @@
 
 static JNINativeMethod gMethods[] = {
     {"setDataSource",       "(Ljava/lang/String;)V",            (void *)android_media_MediaPlayer_setDataSource},
-    {"setDataSource",       "(Ljava/lang/String;Ljava/util/Map;)V",(void *)android_media_MediaPlayer_setDataSourceAndHeaders},
+
+    {
+        "_setDataSource",
+        "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
+        (void *)android_media_MediaPlayer_setDataSourceAndHeaders
+    },
+
     {"setDataSource",       "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},
     {"_setVideoSurfaceOrSurfaceTexture", "()V",                 (void *)android_media_MediaPlayer_setVideoSurfaceOrSurfaceTexture},
     {"prepare",             "()V",                              (void *)android_media_MediaPlayer_prepare},
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
new file mode 100644
index 0000000..27e46a4
--- /dev/null
+++ b/media/jni/android_media_Utils.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011, 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_NDEBUG 0
+#define LOG_TAG "AndroidMediaUtils"
+
+#include <utils/Log.h>
+#include "android_media_Utils.h"
+
+namespace android {
+
+bool ConvertKeyValueArraysToKeyedVector(
+        JNIEnv *env, jobjectArray keys, jobjectArray values,
+        KeyedVector<String8, String8>* keyedVector) {
+
+    int nKeyValuePairs = 0;
+    bool failed = false;
+    if (keys != NULL && values != NULL) {
+        nKeyValuePairs = env->GetArrayLength(keys);
+        failed = (nKeyValuePairs != env->GetArrayLength(values));
+    }
+
+    if (!failed) {
+        failed = ((keys != NULL && values == NULL) ||
+                  (keys == NULL && values != NULL));
+    }
+
+    if (failed) {
+        LOGE("keys and values arrays have different length");
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return false;
+    }
+
+    for (int i = 0; i < nKeyValuePairs; ++i) {
+        // No need to check on the ArrayIndexOutOfBoundsException, since
+        // it won't happen here.
+        jstring key = (jstring) env->GetObjectArrayElement(keys, i);
+        jstring value = (jstring) env->GetObjectArrayElement(values, i);
+
+        const char* keyStr = env->GetStringUTFChars(key, NULL);
+        if (!keyStr) {  // OutOfMemoryError
+            return false;
+        }
+
+        const char* valueStr = env->GetStringUTFChars(value, NULL);
+        if (!valueStr) {  // OutOfMemoryError
+            env->ReleaseStringUTFChars(key, keyStr);
+            return false;
+        }
+
+        keyedVector->add(String8(keyStr), String8(valueStr));
+
+        env->ReleaseStringUTFChars(key, keyStr);
+        env->ReleaseStringUTFChars(value, valueStr);
+        env->DeleteLocalRef(key);
+        env->DeleteLocalRef(value);
+    }
+    return true;
+}
+
+}  // namespace android
+
diff --git a/media/jni/android_media_Utils.h b/media/jni/android_media_Utils.h
new file mode 100644
index 0000000..a2c155a
--- /dev/null
+++ b/media/jni/android_media_Utils.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011, 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_MEDIA_UTILS_H_
+#define _ANDROID_MEDIA_UTILS_H_
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+
+namespace android {
+
+/**
+ * Returns true if the conversion is successful; otherwise, false.
+ */
+bool ConvertKeyValueArraysToKeyedVector(
+    JNIEnv *env, jobjectArray keys, jobjectArray values,
+    KeyedVector<String8, String8>* vector);
+
+};  // namespace android
+
+#endif //  _ANDROID_MEDIA_UTILS_H_
diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp
index 4e22175..28c86426 100644
--- a/media/libmedia/MediaScanner.cpp
+++ b/media/libmedia/MediaScanner.cpp
@@ -135,20 +135,21 @@
         }
         if (type == DT_REG || type == DT_DIR) {
             if (type == DT_DIR) {
+                bool childNoMedia = noMedia;
                 // set noMedia flag on directories with a name that starts with '.'
                 // for example, the Mac ".Trashes" directory
                 if (name[0] == '.')
-                    noMedia = true;
+                    childNoMedia = true;
 
                 // report the directory to the client
                 if (stat(path, &statbuf) == 0) {
-                    client.scanFile(path, statbuf.st_mtime, 0, true, noMedia);
+                    client.scanFile(path, statbuf.st_mtime, 0, true, childNoMedia);
                 }
 
                 // and now process its contents
                 strcat(fileSpot, "/");
                 int err = doProcessDirectory(path, pathRemaining - nameLength - 1, client,
-                        noMedia, exceptionCheck, exceptionEnv);
+                        childNoMedia, exceptionCheck, exceptionEnv);
                 if (err) {
                     // pass exceptions up - ignore other errors
                     if (exceptionCheck && exceptionCheck(exceptionEnv)) goto failure;
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 01fbea1..c1687c4 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -26,6 +26,7 @@
 #include <media/IMediaPlayerService.h>
 #include <media/stagefright/AudioSource.h>
 #include <media/stagefright/AMRWriter.h>
+#include <media/stagefright/AACWriter.h>
 #include <media/stagefright/CameraSource.h>
 #include <media/stagefright/VideoSourceDownSampler.h>
 #include <media/stagefright/CameraSourceTimeLapse.h>
@@ -872,15 +873,21 @@
 }
 
 status_t StagefrightRecorder::startAACRecording() {
-    CHECK(mOutputFormat == OUTPUT_FORMAT_AAC_ADIF ||
-          mOutputFormat == OUTPUT_FORMAT_AAC_ADTS);
+    // FIXME:
+    // Add support for OUTPUT_FORMAT_AAC_ADIF
+    CHECK(mOutputFormat == OUTPUT_FORMAT_AAC_ADTS);
 
     CHECK(mAudioEncoder == AUDIO_ENCODER_AAC);
     CHECK(mAudioSource != AUDIO_SOURCE_CNT);
 
-    CHECK(0 == "AACWriter is not implemented yet");
+    mWriter = new AACWriter(mOutputFd);
+    status_t status = startRawAudioRecording();
+    if (status != OK) {
+        mWriter.clear();
+        mWriter = NULL;
+    }
 
-    return OK;
+    return status;
 }
 
 status_t StagefrightRecorder::startAMRRecording() {
@@ -902,6 +909,16 @@
         }
     }
 
+    mWriter = new AMRWriter(mOutputFd);
+    status_t status = startRawAudioRecording();
+    if (status != OK) {
+        mWriter.clear();
+        mWriter = NULL;
+    }
+    return status;
+}
+
+status_t StagefrightRecorder::startRawAudioRecording() {
     if (mAudioSource >= AUDIO_SOURCE_CNT) {
         LOGE("Invalid audio source: %d", mAudioSource);
         return BAD_VALUE;
@@ -917,7 +934,7 @@
         return UNKNOWN_ERROR;
     }
 
-    mWriter = new AMRWriter(mOutputFd);
+    CHECK(mWriter != 0);
     mWriter->addSource(audioEncoder);
 
     if (mMaxFileDurationUs != 0) {
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 3d463ea..c3e6d65 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -69,6 +69,7 @@
     sp<Surface> mPreviewSurface;
     sp<IMediaRecorderClient> mListener;
     sp<MediaWriter> mWriter, mWriterAux;
+    int mOutputFd, mOutputFdAux;
     sp<AudioSource> mAudioSourceNode;
 
     audio_source_t mAudioSource;
@@ -104,7 +105,6 @@
     sp<CameraSourceTimeLapse> mCameraSourceTimeLapse;
 
     String8 mParams;
-    int mOutputFd, mOutputFdAux;
 
     bool mIsMetaDataStoredInVideoBuffers;
     MediaProfiles *mEncoderProfiles;
@@ -123,6 +123,7 @@
     status_t startMPEG4Recording();
     status_t startAMRRecording();
     status_t startAACRecording();
+    status_t startRawAudioRecording();
     status_t startRTPRecording();
     status_t startMPEG2TSRecording();
     sp<MediaSource> createAudioSource();
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
new file mode 100644
index 0000000..8413208
--- /dev/null
+++ b/media/libstagefright/AACWriter.cpp
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2011 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_NDEBUG 0
+#define LOG_TAG "AACWriter"
+#include <utils/Log.h>
+
+#include <media/stagefright/AACWriter.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/mediarecorder.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <fcntl.h>
+
+namespace android {
+
+AACWriter::AACWriter(const char *filename)
+    : mFd(-1),
+      mInitCheck(NO_INIT),
+      mStarted(false),
+      mPaused(false),
+      mResumed(false),
+      mChannelCount(-1),
+      mSampleRate(-1) {
+
+    LOGV("AACWriter Constructor");
+
+    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR);
+    if (mFd >= 0) {
+        mInitCheck = OK;
+    }
+}
+
+AACWriter::AACWriter(int fd)
+    : mFd(dup(fd)),
+      mInitCheck(mFd < 0? NO_INIT: OK),
+      mStarted(false),
+      mPaused(false),
+      mResumed(false),
+      mChannelCount(-1),
+      mSampleRate(-1) {
+}
+
+AACWriter::~AACWriter() {
+    if (mStarted) {
+        stop();
+    }
+
+    if (mFd != -1) {
+        close(mFd);
+        mFd = -1;
+    }
+}
+
+status_t AACWriter::initCheck() const {
+    return mInitCheck;
+}
+
+static int writeInt8(int fd, uint8_t x) {
+    return ::write(fd, &x, 1);
+}
+
+
+status_t AACWriter::addSource(const sp<MediaSource> &source) {
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mSource != NULL) {
+        LOGE("AAC files only support a single track of audio.");
+        return UNKNOWN_ERROR;
+    }
+
+    sp<MetaData> meta = source->getFormat();
+
+    const char *mime;
+    CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+    CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC));
+    CHECK(meta->findInt32(kKeyChannelCount, &mChannelCount));
+    CHECK(meta->findInt32(kKeySampleRate, &mSampleRate));
+    CHECK(mChannelCount >= 1 && mChannelCount <= 2);
+
+    mSource = source;
+    return OK;
+}
+
+status_t AACWriter::start(MetaData *params) {
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mSource == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    if (mStarted && mPaused) {
+        mPaused = false;
+        mResumed = true;
+        return OK;
+    } else if (mStarted) {
+        // Already started, does nothing
+        return OK;
+    }
+
+    mFrameDurationUs = (kSamplesPerFrame * 1000000LL + (mSampleRate >> 1))
+                            / mSampleRate;
+
+    status_t err = mSource->start();
+
+    if (err != OK) {
+        return err;
+    }
+
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+    mReachedEOS = false;
+    mDone = false;
+
+    pthread_create(&mThread, &attr, ThreadWrapper, this);
+    pthread_attr_destroy(&attr);
+
+    mStarted = true;
+
+    return OK;
+}
+
+status_t AACWriter::pause() {
+    if (!mStarted) {
+        return OK;
+    }
+    mPaused = true;
+    return OK;
+}
+
+status_t AACWriter::stop() {
+    if (!mStarted) {
+        return OK;
+    }
+
+    mDone = true;
+
+    void *dummy;
+    pthread_join(mThread, &dummy);
+
+    status_t err = (status_t) dummy;
+    {
+        status_t status = mSource->stop();
+        if (err == OK &&
+            (status != OK && status != ERROR_END_OF_STREAM)) {
+            err = status;
+        }
+    }
+
+    mStarted = false;
+    return err;
+}
+
+bool AACWriter::exceedsFileSizeLimit() {
+    if (mMaxFileSizeLimitBytes == 0) {
+        return false;
+    }
+    return mEstimatedSizeBytes >= mMaxFileSizeLimitBytes;
+}
+
+bool AACWriter::exceedsFileDurationLimit() {
+    if (mMaxFileDurationLimitUs == 0) {
+        return false;
+    }
+    return mEstimatedDurationUs >= mMaxFileDurationLimitUs;
+}
+
+// static
+void *AACWriter::ThreadWrapper(void *me) {
+    return (void *) static_cast<AACWriter *>(me)->threadFunc();
+}
+
+/*
+* Returns an index into the sample rate table if the
+* given sample rate is found; otherwise, returns -1.
+*/
+static bool getSampleRateTableIndex(int sampleRate, uint8_t* tableIndex) {
+    static const int kSampleRateTable[] = {
+        96000, 88200, 64000, 48000, 44100, 32000,
+        24000, 22050, 16000, 12000, 11025, 8000
+    };
+    const int tableSize =
+        sizeof(kSampleRateTable) / sizeof(kSampleRateTable[0]);
+
+    *tableIndex = 0;
+    for (int index = 0; index < tableSize; ++index) {
+        if (sampleRate == kSampleRateTable[index]) {
+            LOGV("Sample rate: %d and index: %d",
+                sampleRate, index);
+            *tableIndex = index;
+            return true;
+        }
+    }
+
+    LOGE("Sampling rate %d bps is not supported", sampleRate);
+    return false;
+}
+
+/*
+ * ADTS (Audio data transport stream) header structure.
+ * It consists of 7 or 9 bytes (with or without CRC):
+ * 12 bits of syncword 0xFFF, all bits must be 1
+ * 1 bit of field ID. 0 for MPEG-4, and 1 for MPEG-2
+ * 2 bits of MPEG layer. If in MPEG-TS, set to 0
+ * 1 bit of protection absense. Set to 1 if no CRC.
+ * 2 bits of profile code. Set to 1 (The MPEG-4 Audio
+ *   object type minus 1. We are using AAC-LC = 2)
+ * 4 bits of sampling frequency index code (15 is not allowed)
+ * 1 bit of private stream. Set to 0.
+ * 3 bits of channel configuration code. 0 resevered for inband PCM
+ * 1 bit of originality. Set to 0.
+ * 1 bit of home. Set to 0.
+ * 1 bit of copyrighted steam. Set to 0.
+ * 1 bit of copyright start. Set to 0.
+ * 13 bits of frame length. It included 7 ot 9 bytes header length.
+ *   it is set to (protection absense? 7: 9) + size(AAC frame)
+ * 11 bits of buffer fullness. 0x7FF for VBR.
+ * 2 bits of frames count in one packet. Set to 0.
+ */
+status_t AACWriter::writeAdtsHeader(uint32_t frameLength) {
+    uint8_t data = 0xFF;
+    write(mFd, &data, 1);
+
+    const uint8_t kFieldId = 0;
+    const uint8_t kMpegLayer = 0;
+    const uint8_t kProtectionAbsense = 1;  // 1: kAdtsHeaderLength = 7
+    data = 0xF0;
+    data |= (kFieldId << 3);
+    data |= (kMpegLayer << 1);
+    data |= kProtectionAbsense;
+    write(mFd, &data, 1);
+
+    const uint8_t kProfileCode = 1;  // AAC-LC
+    uint8_t kSampleFreqIndex;
+    CHECK(getSampleRateTableIndex(mSampleRate, &kSampleFreqIndex));
+    const uint8_t kPrivateStream = 0;
+    const uint8_t kChannelConfigCode = mChannelCount;
+    data = (kProfileCode << 6);
+    data |= (kSampleFreqIndex << 2);
+    data |= (kPrivateStream << 1);
+    data |= (kChannelConfigCode >> 2);
+    write(mFd, &data, 1);
+
+    // 4 bits from originality to copyright start
+    const uint8_t kCopyright = 0;
+    const uint32_t kFrameLength = frameLength;
+    data = ((kChannelConfigCode & 3) << 6);
+    data |= (kCopyright << 2);
+    data |= ((kFrameLength & 0x1800) >> 11);
+    write(mFd, &data, 1);
+
+    data = ((kFrameLength & 0x07F8) >> 3);
+    write(mFd, &data, 1);
+
+    const uint32_t kBufferFullness = 0x7FF;  // VBR
+    data = ((kFrameLength & 0x07) << 5);
+    data |= ((kBufferFullness & 0x07C0) >> 6);
+    write(mFd, &data, 1);
+
+    const uint8_t kFrameCount = 0;
+    data = ((kBufferFullness & 0x03F) << 2);
+    data |= kFrameCount;
+    write(mFd, &data, 1);
+
+    return OK;
+}
+
+status_t AACWriter::threadFunc() {
+    mEstimatedDurationUs = 0;
+    mEstimatedSizeBytes = 0;
+    int64_t previousPausedDurationUs = 0;
+    int64_t maxTimestampUs = 0;
+    status_t err = OK;
+
+    prctl(PR_SET_NAME, (unsigned long)"AACWriterThread", 0, 0, 0);
+
+    while (!mDone && err == OK) {
+        MediaBuffer *buffer;
+        err = mSource->read(&buffer);
+
+        if (err != OK) {
+            break;
+        }
+
+        if (mPaused) {
+            buffer->release();
+            buffer = NULL;
+            continue;
+        }
+
+        mEstimatedSizeBytes += kAdtsHeaderLength + buffer->range_length();
+        if (exceedsFileSizeLimit()) {
+            buffer->release();
+            buffer = NULL;
+            notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
+            break;
+        }
+
+        int32_t isCodecSpecific = 0;
+        if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecSpecific) && isCodecSpecific) {
+            LOGV("Drop codec specific info buffer");
+            buffer->release();
+            buffer = NULL;
+            continue;
+        }
+
+        int64_t timestampUs;
+        CHECK(buffer->meta_data()->findInt64(kKeyTime, &timestampUs));
+        if (timestampUs > mEstimatedDurationUs) {
+            mEstimatedDurationUs = timestampUs;
+        }
+        if (mResumed) {
+            previousPausedDurationUs += (timestampUs - maxTimestampUs - mFrameDurationUs);
+            mResumed = false;
+        }
+        timestampUs -= previousPausedDurationUs;
+        LOGV("time stamp: %lld, previous paused duration: %lld",
+            timestampUs, previousPausedDurationUs);
+        if (timestampUs > maxTimestampUs) {
+            maxTimestampUs = timestampUs;
+        }
+
+        if (exceedsFileDurationLimit()) {
+            buffer->release();
+            buffer = NULL;
+            notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
+            break;
+        }
+
+        // Each output AAC audio frame to the file contains
+        // 1. an ADTS header, followed by
+        // 2. the compressed audio data.
+        ssize_t dataLength = buffer->range_length();
+        uint8_t *data = (uint8_t *)buffer->data() + buffer->range_offset();
+        if (writeAdtsHeader(kAdtsHeaderLength + dataLength) != OK ||
+            dataLength != write(mFd, data, dataLength)) {
+            err = ERROR_IO;
+        }
+
+        buffer->release();
+        buffer = NULL;
+    }
+
+    close(mFd);
+    mFd = -1;
+    mReachedEOS = true;
+    if (err == ERROR_END_OF_STREAM) {
+        return OK;
+    }
+    return err;
+}
+
+bool AACWriter::reachedEOS() {
+    return mReachedEOS;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 9928f44..e52f6d1 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -505,7 +505,7 @@
 
     // Dequeue buffers and send them to OMX
     for (OMX_U32 i = 0; i < def.nBufferCountActual; i++) {
-        android_native_buffer_t *buf;
+        ANativeWindowBuffer *buf;
         err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf);
         if (err != 0) {
             LOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
@@ -574,7 +574,7 @@
 }
 
 ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() {
-    android_native_buffer_t *buf;
+    ANativeWindowBuffer *buf;
     CHECK_EQ(mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf), 0);
 
     for (size_t i = mBuffers[kPortIndexOutput].size(); i-- > 0;) {
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 2f3e1410..10ce00c 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -6,6 +6,7 @@
 LOCAL_SRC_FILES:=                         \
         ACodec.cpp                        \
         AACExtractor.cpp                  \
+        AACWriter.cpp                     \
         AMRExtractor.cpp                  \
         AMRWriter.cpp                     \
         AVIExtractor.cpp                  \
@@ -48,6 +49,7 @@
         ThrottledSource.cpp               \
         TimeSource.cpp                    \
         TimedEventQueue.cpp               \
+        TimedTextPlayer.cpp               \
         Utils.cpp                         \
         VBRISeeker.cpp                    \
         WAVExtractor.cpp                  \
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 974efa7..cccd0b7 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -28,6 +28,7 @@
 #include "include/NuCachedSource2.h"
 #include "include/ThrottledSource.h"
 #include "include/MPEG2TSExtractor.h"
+#include "include/TimedTextPlayer.h"
 
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
@@ -185,7 +186,8 @@
       mExtractorFlags(0),
       mVideoBuffer(NULL),
       mDecryptHandle(NULL),
-      mLastVideoTimeUs(-1) {
+      mLastVideoTimeUs(-1),
+      mTextPlayer(NULL) {
     CHECK_EQ(mClient.connect(), (status_t)OK);
 
     DataSource::RegisterDefaultSniffers();
@@ -381,10 +383,8 @@
                     mFlags |= AUTO_LOOPING;
                 }
             }
-        }
-
-        if (haveAudio && haveVideo) {
-            break;
+        } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
+            addTextSource(extractor->getTrack(i));
         }
     }
 
@@ -469,6 +469,11 @@
     delete mAudioPlayer;
     mAudioPlayer = NULL;
 
+    if (mTextPlayer != NULL) {
+        delete mTextPlayer;
+        mTextPlayer = NULL;
+    }
+
     mVideoRenderer.clear();
 
     if (mRTSPController != NULL) {
@@ -971,6 +976,11 @@
         mFlags &= ~AUDIO_RUNNING;
     }
 
+    if (mFlags & TEXTPLAYER_STARTED) {
+        mTextPlayer->pause();
+        mFlags &= ~TEXT_RUNNING;
+    }
+
     mFlags &= ~PLAYING;
 
     if (mDecryptHandle != NULL) {
@@ -1119,6 +1129,32 @@
     return OK;
 }
 
+status_t AwesomePlayer::setTimedTextTrackIndex(int32_t index) {
+    if (mTextPlayer != NULL) {
+        if (index >= 0) { // to turn on a text track
+            status_t err = mTextPlayer->setTimedTextTrackIndex(index);
+            if (err != OK) {
+                return err;
+            }
+
+            mFlags |= TEXT_RUNNING;
+            mFlags |= TEXTPLAYER_STARTED;
+            return OK;
+        } else { // to turn off the text track display
+            if (mFlags  & TEXT_RUNNING) {
+                mFlags &= ~TEXT_RUNNING;
+            }
+            if (mFlags  & TEXTPLAYER_STARTED) {
+                mFlags &= ~TEXTPLAYER_STARTED;
+            }
+
+            return mTextPlayer->setTimedTextTrackIndex(index);
+        }
+    } else {
+        return INVALID_OPERATION;
+    }
+}
+
 // static
 void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) {
     static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone();
@@ -1155,6 +1191,10 @@
 
     seekAudioIfNecessary_l();
 
+    if (mFlags & TEXTPLAYER_STARTED) {
+        mTextPlayer->seekTo(mSeekTimeUs);
+    }
+
     if (!(mFlags & PLAYING)) {
         LOGV("seeking while paused, sending SEEK_COMPLETE notification"
              " immediately.");
@@ -1193,6 +1233,16 @@
     mAudioTrack = source;
 }
 
+void AwesomePlayer::addTextSource(sp<MediaSource> source) {
+    CHECK(source != NULL);
+
+    if (mTextPlayer == NULL) {
+        mTextPlayer = new TimedTextPlayer(this, mListener, &mQueue);
+    }
+
+    mTextPlayer->addTextSource(source);
+}
+
 status_t AwesomePlayer::initAudioDecoder() {
     sp<MetaData> meta = mAudioTrack->getFormat();
 
@@ -1472,6 +1522,11 @@
         }
     }
 
+    if ((mFlags & TEXTPLAYER_STARTED) && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) {
+        mTextPlayer->resume();
+        mFlags |= TEXT_RUNNING;
+    }
+
     TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
 
     if (mFlags & FIRST_FRAME) {
@@ -1906,7 +1961,10 @@
 }
 
 status_t AwesomePlayer::setParameter(int key, const Parcel &request) {
-    return OK;
+    if (key == KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX) {
+        return setTimedTextTrackIndex(request.readInt32());
+    }
+    return ERROR_UNSUPPORTED;
 }
 
 status_t AwesomePlayer::getParameter(int key, Parcel *reply) {
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 8787214..c79d02e 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -19,6 +19,8 @@
 
 #include "include/MPEG4Extractor.h"
 #include "include/SampleTable.h"
+#include "include/ESDS.h"
+#include "include/TimedTextPlayer.h"
 
 #include <arpa/inet.h>
 
@@ -29,7 +31,6 @@
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/DataSource.h>
-#include "include/ESDS.h"
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
@@ -832,6 +833,33 @@
             mLastTrack->meta->setInt64(
                     kKeyDuration, (duration * 1000000) / mLastTrack->timescale);
 
+            uint8_t lang[2];
+            off64_t lang_offset;
+            if (version == 1) {
+                lang_offset = timescale_offset + 4 + 8;
+            } else if (version == 0) {
+                lang_offset = timescale_offset + 4 + 4;
+            } else {
+                return ERROR_IO;
+            }
+
+            if (mDataSource->readAt(lang_offset, &lang, sizeof(lang))
+                    < (ssize_t)sizeof(lang)) {
+                return ERROR_IO;
+            }
+
+            // To get the ISO-639-2/T three character language code
+            // 1 bit pad followed by 3 5-bits characters. Each character
+            // is packed as the difference between its ASCII value and 0x60.
+            char lang_code[4];
+            lang_code[0] = ((lang[0] >> 2) & 0x1f) + 0x60;
+            lang_code[1] = ((lang[0] & 0x3) << 3 | (lang[1] >> 5)) + 0x60;
+            lang_code[2] = (lang[1] & 0x1f) + 0x60;
+            lang_code[3] = '\0';
+
+            mLastTrack->meta->setCString(
+                    kKeyMediaLanguage, lang_code);
+
             *offset += chunk_size;
             break;
         }
@@ -1295,6 +1323,14 @@
             return parseDrmSINF(offset, data_offset);
         }
 
+        case FOURCC('t', 'x', '3', 'g'):
+        {
+            mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_TEXT_3GPP);
+
+            *offset += chunk_size;
+            break;
+        }
+
         default:
         {
             *offset += chunk_size;
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 8ca6ee8..8cd08bc 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -47,4 +47,6 @@
 
 const char *MEDIA_MIMETYPE_CONTAINER_WVM = "video/wvm";
 
+const char *MEDIA_MIMETYPE_TEXT_3GPP = "text/3gpp-tt";
+
 }  // namespace android
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index dc86885..81f2e47 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -450,6 +450,11 @@
         }
 
         size_t avail = mCache->totalSize() - delta;
+
+        if (avail > size) {
+            avail = size;
+        }
+
         mCache->copy(delta, data, avail);
 
         return avail;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 06352f4..78d13b2 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1830,7 +1830,7 @@
 
     // Dequeue buffers and send them to OMX
     for (OMX_U32 i = 0; i < def.nBufferCountActual; i++) {
-        android_native_buffer_t* buf;
+        ANativeWindowBuffer* buf;
         err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf);
         if (err != 0) {
             LOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
@@ -1900,7 +1900,7 @@
 
 OMXCodec::BufferInfo* OMXCodec::dequeueBufferFromNativeWindow() {
     // Dequeue the next buffer from the native window.
-    android_native_buffer_t* buf;
+    ANativeWindowBuffer* buf;
     int err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf);
     if (err != 0) {
       CODEC_LOGE("dequeueBuffer failed w/ error 0x%08x", err);
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 7621f2c..4c3dc47 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -27,6 +27,7 @@
 #include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/MediaDefs.h>
 
 namespace android {
 
@@ -429,6 +430,7 @@
 
     // The overall duration is the duration of the longest track.
     int64_t maxDurationUs = 0;
+    String8 timedTextLang;
     for (size_t i = 0; i < numTracks; ++i) {
         sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
 
@@ -452,10 +454,22 @@
 
                 CHECK(trackMeta->findInt32(kKeyWidth, &videoWidth));
                 CHECK(trackMeta->findInt32(kKeyHeight, &videoHeight));
+            } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
+                const char *lang;
+                trackMeta->findCString(kKeyMediaLanguage, &lang);
+                timedTextLang.append(String8(lang));
+                timedTextLang.append(String8(":"));
             }
         }
     }
 
+    // To save the language codes for all timed text tracks
+    // If multiple text tracks present, the format will look
+    // like "eng:chi"
+    if (!timedTextLang.isEmpty()) {
+        mMetaData.add(METADATA_KEY_TIMED_TEXT_LANGUAGES, timedTextLang);
+    }
+
     // The duration value is a string representing the duration in ms.
     sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000);
     mMetaData.add(METADATA_KEY_DURATION, String8(tmp));
diff --git a/media/libstagefright/TimedTextPlayer.cpp b/media/libstagefright/TimedTextPlayer.cpp
new file mode 100644
index 0000000..1ac22cb
--- /dev/null
+++ b/media/libstagefright/TimedTextPlayer.cpp
@@ -0,0 +1,252 @@
+ /*
+ * Copyright (C) 2011 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_NDEBUG 0
+#define LOG_TAG "TimedTextPlayer"
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/Utils.h>
+#include "include/AwesomePlayer.h"
+#include "include/TimedTextPlayer.h"
+
+namespace android {
+
+struct TimedTextEvent : public TimedEventQueue::Event {
+    TimedTextEvent(
+            TimedTextPlayer *player,
+            void (TimedTextPlayer::*method)())
+        : mPlayer(player),
+          mMethod(method) {
+    }
+
+protected:
+    virtual ~TimedTextEvent() {}
+
+    virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
+        (mPlayer->*mMethod)();
+    }
+
+private:
+    TimedTextPlayer *mPlayer;
+    void (TimedTextPlayer::*mMethod)();
+
+    TimedTextEvent(const TimedTextEvent &);
+    TimedTextEvent &operator=(const TimedTextEvent &);
+};
+
+TimedTextPlayer::TimedTextPlayer(
+        AwesomePlayer *observer,
+        const wp<MediaPlayerBase> &listener,
+        TimedEventQueue *queue)
+    : mSource(NULL),
+      mSeekTimeUs(0),
+      mStarted(false),
+      mTextEventPending(false),
+      mQueue(queue),
+      mListener(listener),
+      mObserver(observer),
+      mTextBuffer(NULL) {
+    mTextEvent = new TimedTextEvent(this, &TimedTextPlayer::onTextEvent);
+}
+
+TimedTextPlayer::~TimedTextPlayer() {
+    if (mStarted) {
+        reset();
+    }
+
+    mTextTrackVector.clear();
+}
+
+status_t TimedTextPlayer::start(uint8_t index) {
+    CHECK(!mStarted);
+
+    if (index >= mTextTrackVector.size()) {
+        LOGE("Incorrect text track index");
+        return BAD_VALUE;
+    }
+
+    mSource = mTextTrackVector.itemAt(index);
+
+    status_t err = mSource->start();
+
+    if (err != OK) {
+        return err;
+    }
+
+    int64_t positionUs;
+    mObserver->getPosition(&positionUs);
+    seekTo(positionUs);
+
+    postTextEvent();
+
+    mStarted = true;
+
+    return OK;
+}
+
+void TimedTextPlayer::pause() {
+    CHECK(mStarted);
+
+    cancelTextEvent();
+}
+
+void TimedTextPlayer::resume() {
+    CHECK(mStarted);
+
+    postTextEvent();
+}
+
+void TimedTextPlayer::reset() {
+    CHECK(mStarted);
+
+    // send an empty text to clear the screen
+    notifyListener(MEDIA_TIMED_TEXT);
+
+    cancelTextEvent();
+
+    mSeeking = false;
+    mStarted = false;
+
+    if (mTextBuffer != NULL) {
+        mTextBuffer->release();
+        mTextBuffer = NULL;
+    }
+
+    if (mSource != NULL) {
+        mSource->stop();
+        mSource.clear();
+        mSource = NULL;
+    }
+}
+
+status_t TimedTextPlayer::seekTo(int64_t time_us) {
+    Mutex::Autolock autoLock(mLock);
+
+    mSeeking = true;
+    mSeekTimeUs = time_us;
+
+    return OK;
+}
+
+status_t TimedTextPlayer::setTimedTextTrackIndex(int32_t index) {
+    if (index >= (int)(mTextTrackVector.size())) {
+        return BAD_VALUE;
+    }
+
+    if (mStarted) {
+        reset();
+    }
+
+    if (index >= 0) {
+        return start(index);
+    }
+    return OK;
+}
+
+void TimedTextPlayer::onTextEvent() {
+    Mutex::Autolock autoLock(mLock);
+
+    if (!mTextEventPending) {
+        return;
+    }
+    mTextEventPending = false;
+
+    MediaSource::ReadOptions options;
+    if (mSeeking) {
+        options.setSeekTo(mSeekTimeUs,
+                MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+        mSeeking = false;
+
+        if (mTextBuffer != NULL) {
+            mTextBuffer->release();
+            mTextBuffer = NULL;
+        }
+
+        notifyListener(MEDIA_TIMED_TEXT); //empty text to clear the screen
+    }
+
+    if (mTextBuffer != NULL) {
+        uint8_t *tmp = (uint8_t *)(mTextBuffer->data());
+        size_t len = (*tmp) << 8 | (*(tmp + 1));
+
+        notifyListener(MEDIA_TIMED_TEXT,
+                       tmp + 2,
+                       len);
+
+        mTextBuffer->release();
+        mTextBuffer = NULL;
+
+    }
+
+    if (mSource->read(&mTextBuffer, &options) != OK) {
+        return;
+    }
+
+    int64_t positionUs, timeUs;
+    mObserver->getPosition(&positionUs);
+    mTextBuffer->meta_data()->findInt64(kKeyTime, &timeUs);
+
+    //send the text now
+    if (timeUs <= positionUs + 100000ll) {
+        postTextEvent();
+    } else {
+        postTextEvent(timeUs - positionUs - 100000ll);
+    }
+}
+
+void TimedTextPlayer::postTextEvent(int64_t delayUs) {
+    if (mTextEventPending) {
+        return;
+    }
+
+    mTextEventPending = true;
+    mQueue->postEventWithDelay(mTextEvent, delayUs < 0 ? 10000 : delayUs);
+}
+
+void TimedTextPlayer::cancelTextEvent() {
+    mQueue->cancelEvent(mTextEvent->eventID());
+    mTextEventPending = false;
+}
+
+void TimedTextPlayer::addTextSource(sp<MediaSource> source) {
+    mTextTrackVector.add(source);
+}
+
+void TimedTextPlayer::notifyListener(
+        int msg, const void *data, size_t size) {
+    if (mListener != NULL) {
+        sp<MediaPlayerBase> listener = mListener.promote();
+
+        if (listener != NULL) {
+            if (size > 0) {
+                mData.freeData();
+                mData.write(data, size);
+
+                listener->sendEvent(msg, 0, 0, &mData);
+            } else { // send an empty timed text to clear the screen
+                listener->sendEvent(msg);
+            }
+        }
+    }
+}
+}
diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
index 208431c..d2e3eaa 100644
--- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp
+++ b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
@@ -234,6 +234,23 @@
             mConfig->aacPlusUpsamplingFactor, mConfig->desiredChannels);
 
         CHECK(mNumDecodedBuffers > 0);
+
+        if (decoderErr != MP4AUDEC_SUCCESS) {
+            // If decoding fails this early, the fields in mConfig may
+            // not be valid and we cannot recover.
+
+            LOGE("Unable to decode aac content, decoder returned error %d",
+                 decoderErr);
+
+            buffer->release();
+            buffer = NULL;
+
+            mInputBuffer->release();
+            mInputBuffer = NULL;
+
+            return ERROR_UNSUPPORTED;
+        }
+
         if (mNumDecodedBuffers == 1) {
             mUpsamplingFactor = mConfig->aacPlusUpsamplingFactor;
             // Check on the sampling rate to see whether it is changed.
diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
index e4ff128..0bff52d 100644
--- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
@@ -84,7 +84,7 @@
     params.sampleRate = mSampleRate;
     params.bitRate = mBitRate;
     params.nChannels = mChannels;
-    params.adtsUsed = 0;  // For MP4 file, don't use adts format$
+    params.adtsUsed = 0;  // We add adts header in the file writer if needed.
     if (VO_ERR_NONE != mApiHandle->SetParam(mEncoderHandle, VO_PID_AAC_ENCPARAM,  &params)) {
         LOGE("Failed to set AAC encoder parameters");
         return UNKNOWN_ERROR;
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index 3b92e5d..4b72a53 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -187,8 +187,7 @@
 
 status_t ColorConverter::convertYUV420Planar(
         const BitmapParams &src, const BitmapParams &dst) {
-    if (!((dst.mWidth & 1) == 0
-            && (src.mCropLeft & 1) == 0
+    if (!((src.mCropLeft & 1) == 0
             && src.cropWidth() == dst.cropWidth()
             && src.cropHeight() == dst.cropHeight())) {
         return ERROR_UNSUPPORTED;
@@ -196,8 +195,8 @@
 
     uint8_t *kAdjustedClip = initClip();
 
-    uint32_t *dst_ptr = (uint32_t *)dst.mBits
-        + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
+    uint16_t *dst_ptr = (uint16_t *)dst.mBits
+        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
     const uint8_t *src_y =
         (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
@@ -260,7 +259,11 @@
                 | ((kAdjustedClip[g2] >> 2) << 5)
                 | (kAdjustedClip[b2] >> 3);
 
-            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+            if (x + 1 < src.cropWidth()) {
+                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
+            } else {
+                dst_ptr[x] = rgb1;
+            }
         }
 
         src_y += src.mWidth;
@@ -270,7 +273,7 @@
             src_v += src.mWidth / 2;
         }
 
-        dst_ptr += dst.mWidth / 2;
+        dst_ptr += dst.mWidth;
     }
 
     return OK;
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 31afc43..3b13476 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -108,7 +108,7 @@
 
 void SoftwareRenderer::render(
         const void *data, size_t size, void *platformPrivate) {
-    android_native_buffer_t *buf;
+    ANativeWindowBuffer *buf;
     int err;
     if ((err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf)) != 0) {
         LOGW("Surface::dequeueBuffer returned error %d", err);
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 2c17d92..fd3ddf7 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -44,6 +44,8 @@
 class DrmManagerClinet;
 class DecryptHandle;
 
+class TimedTextPlayer;
+
 struct AwesomeRenderer : public RefBase {
     AwesomeRenderer() {}
 
@@ -99,36 +101,41 @@
     void postAudioEOS(int64_t delayUs = 0ll);
     void postAudioSeekComplete();
 
+    status_t setTimedTextTrackIndex(int32_t index);
+
 private:
     friend struct AwesomeEvent;
     friend struct PreviewPlayer;
 
     enum {
-        PLAYING             = 1,
-        LOOPING             = 2,
-        FIRST_FRAME         = 4,
-        PREPARING           = 8,
-        PREPARED            = 16,
-        AT_EOS              = 32,
-        PREPARE_CANCELLED   = 64,
-        CACHE_UNDERRUN      = 128,
-        AUDIO_AT_EOS        = 256,
-        VIDEO_AT_EOS        = 512,
-        AUTO_LOOPING        = 1024,
+        PLAYING             = 0x01,
+        LOOPING             = 0x02,
+        FIRST_FRAME         = 0x04,
+        PREPARING           = 0x08,
+        PREPARED            = 0x10,
+        AT_EOS              = 0x20,
+        PREPARE_CANCELLED   = 0x40,
+        CACHE_UNDERRUN      = 0x80,
+        AUDIO_AT_EOS        = 0x0100,
+        VIDEO_AT_EOS        = 0x0200,
+        AUTO_LOOPING        = 0x0400,
 
         // We are basically done preparing but are currently buffering
         // sufficient data to begin playback and finish the preparation phase
         // for good.
-        PREPARING_CONNECTED = 2048,
+        PREPARING_CONNECTED = 0x0800,
 
         // We're triggering a single video event to display the first frame
         // after the seekpoint.
-        SEEK_PREVIEW        = 4096,
+        SEEK_PREVIEW        = 0x1000,
 
-        AUDIO_RUNNING       = 8192,
-        AUDIOPLAYER_STARTED = 16384,
+        AUDIO_RUNNING       = 0x2000,
+        AUDIOPLAYER_STARTED = 0x4000,
 
-        INCOGNITO           = 32768,
+        INCOGNITO           = 0x8000,
+
+        TEXT_RUNNING        = 0x10000,
+        TEXTPLAYER_STARTED  = 0x20000,
     };
 
     mutable Mutex mLock;
@@ -222,6 +229,7 @@
     sp<DecryptHandle> mDecryptHandle;
 
     int64_t mLastVideoTimeUs;
+    TimedTextPlayer *mTextPlayer;
 
     status_t setDataSource_l(
             const char *uri,
@@ -244,6 +252,8 @@
     void setVideoSource(sp<MediaSource> source);
     status_t initVideoDecoder(uint32_t flags = 0);
 
+    void addTextSource(sp<MediaSource> source);
+
     void onStreamDone();
 
     void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0);
diff --git a/media/libstagefright/include/TimedTextPlayer.h b/media/libstagefright/include/TimedTextPlayer.h
new file mode 100644
index 0000000..ac41b4f
--- /dev/null
+++ b/media/libstagefright/include/TimedTextPlayer.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2011 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 TIMEDTEXT_PLAYER_H_
+
+#define TIMEDTEXT_PLAYER_H_
+
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/foundation/ABase.h>
+
+#include "include/TimedEventQueue.h"
+
+namespace android {
+
+class MediaSource;
+class AwesomePlayer;
+class MediaBuffer;
+
+class TimedTextPlayer {
+public:
+    TimedTextPlayer(AwesomePlayer *observer,
+                    const wp<MediaPlayerBase> &listener,
+                    TimedEventQueue *queue);
+
+    virtual ~TimedTextPlayer();
+
+    // index: the index of the text track which will
+    // be turned on
+    status_t start(uint8_t index);
+
+    void pause();
+
+    void resume();
+
+    status_t seekTo(int64_t time_us);
+
+    void addTextSource(sp<MediaSource> source);
+
+    status_t setTimedTextTrackIndex(int32_t index);
+
+private:
+    Mutex mLock;
+
+    sp<MediaSource> mSource;
+
+    bool mSeeking;
+    int64_t mSeekTimeUs;
+
+    bool mStarted;
+
+    sp<TimedEventQueue::Event> mTextEvent;
+    bool mTextEventPending;
+
+    TimedEventQueue *mQueue;
+
+    wp<MediaPlayerBase> mListener;
+    AwesomePlayer *mObserver;
+
+    MediaBuffer *mTextBuffer;
+    Parcel mData;
+
+    Vector<sp<MediaSource> > mTextTrackVector;
+
+    void reset();
+
+    void onTextEvent();
+    void postTextEvent(int64_t delayUs = -1);
+    void cancelTextEvent();
+
+    void notifyListener(
+            int msg, const void *data = NULL, size_t size = 0);
+
+    DISALLOW_EVIL_CONSTRUCTORS(TimedTextPlayer);
+};
+
+}  // namespace android
+
+#endif  // TIMEDTEXT_PLAYER_H_
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 64266b8..e1b9991 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -591,7 +591,8 @@
         // AudioSpecificInfo (with size prefix) follows
     };
 
-    CHECK(asiSize < 128);
+    // Make sure all sizes can be coded in a single byte.
+    CHECK(asiSize + 22 - 2 < 128);
     size_t esdsSize = sizeof(kStaticESDS) + asiSize + 1;
     uint8_t *esds = new uint8_t[esdsSize];
     memcpy(esds, kStaticESDS, sizeof(kStaticESDS));
@@ -599,6 +600,11 @@
     *ptr++ = asiSize;
     memcpy(ptr, asi, asiSize);
 
+    // Increment by codecPrivateSize less 2 bytes that are accounted for
+    // already in lengths of 22/17
+    esds[1] += asiSize - 2;
+    esds[6] += asiSize - 2;
+
     meta->setData(kKeyESDS, 0, esds, esdsSize);
 
     delete[] esds;
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 1ffcd56..1123e16 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -225,7 +225,7 @@
 
 #ifndef EGL_ANDROID_image_native_buffer
 #define EGL_ANDROID_image_native_buffer 1
-struct android_native_buffer_t;
+struct ANativeWindowBuffer;
 #define EGL_NATIVE_BUFFER_ANDROID       0x3140  /* eglCreateImageKHR target */
 #endif
 
diff --git a/opengl/java/com/google/android/gles_jni/EGLImpl.java b/opengl/java/com/google/android/gles_jni/EGLImpl.java
index 8a7124d..f162d40 100644
--- a/opengl/java/com/google/android/gles_jni/EGLImpl.java
+++ b/opengl/java/com/google/android/gles_jni/EGLImpl.java
@@ -18,10 +18,10 @@
 
 import javax.microedition.khronos.egl.*;
 
+import android.graphics.SurfaceTexture;
 import android.view.Surface;
 import android.view.SurfaceView;
 import android.view.SurfaceHolder;
-import android.view.View;
 
 public class EGLImpl implements EGL10 {
     private EGLContextImpl mContext = new EGLContextImpl(-1);
@@ -71,19 +71,28 @@
     }
 
     public EGLSurface eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list) {
-        Surface sur;
+        Surface sur = null;
         if (native_window instanceof SurfaceView) {
             SurfaceView surfaceView = (SurfaceView)native_window;
             sur = surfaceView.getHolder().getSurface();
         } else if (native_window instanceof SurfaceHolder) {
             SurfaceHolder holder = (SurfaceHolder)native_window;
             sur = holder.getSurface();
+        }
+
+        int eglSurfaceId;
+        if (sur != null) {
+            eglSurfaceId = _eglCreateWindowSurface(display, config, sur, attrib_list);
+        } else if (native_window instanceof SurfaceTexture) {
+            eglSurfaceId = _eglCreateWindowSurfaceTexture(display, config,
+                    ((SurfaceTexture) native_window).mSurfaceTexture, attrib_list);
         } else {
             throw new java.lang.UnsupportedOperationException(
                 "eglCreateWindowSurface() can only be called with an instance of " +
-                "SurfaceView or SurfaceHolder at the moment, this will be fixed later.");
+                "SurfaceView, SurfaceHolder or SurfaceTexture at the moment, " + 
+                "this will be fixed later.");
         }
-        int eglSurfaceId = _eglCreateWindowSurface(display, config, sur, attrib_list);
+
         if (eglSurfaceId == 0) {
             return EGL10.EGL_NO_SURFACE;
         }
@@ -134,6 +143,7 @@
     private native int _eglCreatePbufferSurface(EGLDisplay display, EGLConfig config, int[] attrib_list);
     private native void _eglCreatePixmapSurface(EGLSurface sur, EGLDisplay display, EGLConfig config, Object native_pixmap, int[] attrib_list);
     private native int _eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
+    private native int _eglCreateWindowSurfaceTexture(EGLDisplay display, EGLConfig config, int native_window, int[] attrib_list);
     private native int _eglGetDisplay(Object native_display);
     private native int _eglGetCurrentContext();
     private native int _eglGetCurrentDisplay();
diff --git a/opengl/libagl/TextureObjectManager.cpp b/opengl/libagl/TextureObjectManager.cpp
index bbb82fc..022de09 100644
--- a/opengl/libagl/TextureObjectManager.cpp
+++ b/opengl/libagl/TextureObjectManager.cpp
@@ -145,7 +145,7 @@
     return NO_ERROR;
 }
 
-status_t EGLTextureObject::setImage(android_native_buffer_t* native_buffer)
+status_t EGLTextureObject::setImage(ANativeWindowBuffer* native_buffer)
 {
     GGLSurface sur;
     sur.version = sizeof(GGLSurface);
diff --git a/opengl/libagl/TextureObjectManager.h b/opengl/libagl/TextureObjectManager.h
index 70e3bef..de9e03e 100644
--- a/opengl/libagl/TextureObjectManager.h
+++ b/opengl/libagl/TextureObjectManager.h
@@ -48,7 +48,7 @@
                    ~EGLTextureObject();
 
     status_t    setSurface(GGLSurface const* s);
-    status_t    setImage(android_native_buffer_t* buffer);
+    status_t    setImage(ANativeWindowBuffer* buffer);
     void        setImageBits(void* vaddr) { surface.data = (GGLubyte*)vaddr; }
 
     status_t            reallocate(GLint level,
@@ -80,7 +80,7 @@
     GLint               crop_rect[4];
     GLint               generate_mipmap;
     GLint               direct;
-    android_native_buffer_t* buffer;
+    ANativeWindowBuffer* buffer;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 40fa148..0d03361 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -230,11 +230,11 @@
     virtual     EGLBoolean  setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
     
 private:
-    status_t lock(android_native_buffer_t* buf, int usage, void** vaddr);
-    status_t unlock(android_native_buffer_t* buf);
+    status_t lock(ANativeWindowBuffer* buf, int usage, void** vaddr);
+    status_t unlock(ANativeWindowBuffer* buf);
     ANativeWindow*   nativeWindow;
-    android_native_buffer_t*   buffer;
-    android_native_buffer_t*   previousBuffer;
+    ANativeWindowBuffer*   buffer;
+    ANativeWindowBuffer*   previousBuffer;
     gralloc_module_t const*    module;
     int width;
     int height;
@@ -322,8 +322,8 @@
     };
     
     void copyBlt(
-            android_native_buffer_t* dst, void* dst_vaddr,
-            android_native_buffer_t* src, void const* src_vaddr,
+            ANativeWindowBuffer* dst, void* dst_vaddr,
+            ANativeWindowBuffer* src, void const* src_vaddr,
             const Region& clip);
 
     Rect dirtyRegion;
@@ -415,7 +415,7 @@
 }
 
 status_t egl_window_surface_v2_t::lock(
-        android_native_buffer_t* buf, int usage, void** vaddr)
+        ANativeWindowBuffer* buf, int usage, void** vaddr)
 {
     int err;
 
@@ -425,7 +425,7 @@
     return err;
 }
 
-status_t egl_window_surface_v2_t::unlock(android_native_buffer_t* buf)
+status_t egl_window_surface_v2_t::unlock(ANativeWindowBuffer* buf)
 {
     if (!buf) return BAD_VALUE;
     int err = NO_ERROR;
@@ -436,11 +436,10 @@
 }
 
 void egl_window_surface_v2_t::copyBlt(
-        android_native_buffer_t* dst, void* dst_vaddr,
-        android_native_buffer_t* src, void const* src_vaddr,
+        ANativeWindowBuffer* dst, void* dst_vaddr,
+        ANativeWindowBuffer* src, void const* src_vaddr,
         const Region& clip)
 {
-    // FIXME: use copybit if possible
     // NOTE: dst and src must be the same format
     
     Region::const_iterator cur = clip.begin();
@@ -2004,12 +2003,12 @@
         return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
     }
 
-    android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer;
+    ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)buffer;
 
     if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
         return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
 
-    if (native_buffer->common.version != sizeof(android_native_buffer_t))
+    if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
         return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
 
     switch (native_buffer->format) {
@@ -2035,12 +2034,12 @@
         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
     }
 
-    android_native_buffer_t* native_buffer = (android_native_buffer_t*)img;
+    ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)img;
 
     if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
 
-    if (native_buffer->common.version != sizeof(android_native_buffer_t))
+    if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
 
     native_buffer->common.decRef(&native_buffer->common);
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index eb96895..8eb17c4 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -126,7 +126,7 @@
     for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
         if (c->rasterizer.state.texture[i].enable) {
             texture_unit_t& u(c->textures.tmu[i]);
-            android_native_buffer_t* native_buffer = u.texture->buffer;
+            ANativeWindowBuffer* native_buffer = u.texture->buffer;
             if (native_buffer) {
                 c->rasterizer.procs.activeTexture(c, i);
                 hw_module_t const* pModule;
@@ -154,7 +154,7 @@
     for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
         if (c->rasterizer.state.texture[i].enable) {
             texture_unit_t& u(c->textures.tmu[i]);
-            android_native_buffer_t* native_buffer = u.texture->buffer;
+            ANativeWindowBuffer* native_buffer = u.texture->buffer;
             if (native_buffer) {
                 c->rasterizer.procs.activeTexture(c, i);
                 hw_module_t const* pModule;
@@ -1615,12 +1615,12 @@
         return;
     }
 
-    android_native_buffer_t* native_buffer = (android_native_buffer_t*)image;
+    ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)image;
     if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) {
         ogles_error(c, GL_INVALID_VALUE);
         return;
     }
-    if (native_buffer->common.version != sizeof(android_native_buffer_t)) {
+    if (native_buffer->common.version != sizeof(ANativeWindowBuffer)) {
         ogles_error(c, GL_INVALID_VALUE);
         return;
     }
@@ -1643,12 +1643,12 @@
         return;
     }
 
-    android_native_buffer_t* native_buffer = (android_native_buffer_t*)image;
+    ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)image;
     if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) {
         ogles_error(c, GL_INVALID_VALUE);
         return;
     }
-    if (native_buffer->common.version != sizeof(android_native_buffer_t)) {
+    if (native_buffer->common.version != sizeof(ANativeWindowBuffer)) {
         ogles_error(c, GL_INVALID_VALUE);
         return;
     }
diff --git a/opengl/libagl2/src/egl.cpp b/opengl/libagl2/src/egl.cpp
index ba771c3..0d02ce6 100644
--- a/opengl/libagl2/src/egl.cpp
+++ b/opengl/libagl2/src/egl.cpp
@@ -211,11 +211,11 @@
     virtual     EGLBoolean  setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
 
 private:
-    status_t lock(android_native_buffer_t* buf, int usage, void** vaddr);
-    status_t unlock(android_native_buffer_t* buf);
+    status_t lock(ANativeWindowBuffer* buf, int usage, void** vaddr);
+    status_t unlock(ANativeWindowBuffer* buf);
     ANativeWindow*   nativeWindow;
-    android_native_buffer_t*   buffer;
-    android_native_buffer_t*   previousBuffer;
+    ANativeWindowBuffer*   buffer;
+    ANativeWindowBuffer*   previousBuffer;
     gralloc_module_t const*    module;
     int width;
     int height;
@@ -307,8 +307,8 @@
     };
 
     void copyBlt(
-            android_native_buffer_t* dst, void* dst_vaddr,
-            android_native_buffer_t* src, void const* src_vaddr,
+            ANativeWindowBuffer* dst, void* dst_vaddr,
+            ANativeWindowBuffer* src, void const* src_vaddr,
             const Region& clip);
 
     Rect dirtyRegion;
@@ -407,7 +407,7 @@
 }
 
 status_t egl_window_surface_v2_t::lock(
-        android_native_buffer_t* buf, int usage, void** vaddr)
+        ANativeWindowBuffer* buf, int usage, void** vaddr)
 {
     int err;
 
@@ -417,7 +417,7 @@
     return err;
 }
 
-status_t egl_window_surface_v2_t::unlock(android_native_buffer_t* buf)
+status_t egl_window_surface_v2_t::unlock(ANativeWindowBuffer* buf)
 {
     if (!buf) return BAD_VALUE;
     int err = NO_ERROR;
@@ -428,11 +428,10 @@
 }
 
 void egl_window_surface_v2_t::copyBlt(
-        android_native_buffer_t* dst, void* dst_vaddr,
-        android_native_buffer_t* src, void const* src_vaddr,
+        ANativeWindowBuffer* dst, void* dst_vaddr,
+        ANativeWindowBuffer* src, void const* src_vaddr,
         const Region& clip)
 {
-    // FIXME: use copybit if possible
     // NOTE: dst and src must be the same format
 
     Region::const_iterator cur = clip.begin();
@@ -2106,12 +2105,12 @@
         return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
     }
 
-    android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer;
+    ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)buffer;
 
     if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
         return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
 
-    if (native_buffer->common.version != sizeof(android_native_buffer_t))
+    if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
         return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
 
     switch (native_buffer->format) {
@@ -2137,12 +2136,12 @@
         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
     }
 
-    android_native_buffer_t* native_buffer = (android_native_buffer_t*)img;
+    ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)img;
 
     if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
 
-    if (native_buffer->common.version != sizeof(android_native_buffer_t))
+    if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
 
     native_buffer->common.decRef(&native_buffer->common);
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_background.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_background.9.png
deleted file mode 100644
index a4be298..0000000
--- a/packages/SystemUI/res/drawable-hdpi/status_bar_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
new file mode 100644
index 0000000..87d1944
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_veto_normal.png b/packages/SystemUI/res/drawable-hdpi/status_bar_veto_normal.png
new file mode 100644
index 0000000..3b7c9c7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_veto_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_veto_pressed.png b/packages/SystemUI/res/drawable-hdpi/status_bar_veto_pressed.png
new file mode 100644
index 0000000..653acbb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_veto_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/statusbar_background.9.png b/packages/SystemUI/res/drawable-hdpi/statusbar_background.9.png
new file mode 100644
index 0000000..a933833
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/statusbar_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_background.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_background.9.png
deleted file mode 100644
index eb7c1a4..0000000
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/statusbar_background.9.png b/packages/SystemUI/res/drawable-mdpi/statusbar_background.9.png
new file mode 100644
index 0000000..6c588f7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/statusbar_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
new file mode 100644
index 0000000..eba4480
--- /dev/null
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 2011, 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.
+*/
+-->
+
+<com.android.systemui.statusbar.phone.NavigationBarView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    >
+
+    <LinearLayout android:id="@+id/rot0"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:paddingLeft="8dip"
+        android:paddingRight="8dip"
+        android:background="#FF000000"
+        android:orientation="horizontal"
+        >
+
+        <!-- navigation controls -->
+        <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:src="@drawable/ic_sysbar_back"
+            systemui:keyCode="4"
+            android:layout_weight="1"
+            />
+        <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:src="@drawable/ic_sysbar_home"
+            systemui:keyCode="3"
+            android:layout_weight="1"
+            />
+        <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:src="@drawable/ic_sysbar_menu"
+            systemui:keyCode="82"
+            android:layout_weight="1"
+            />
+    </LinearLayout>
+
+    <LinearLayout android:id="@+id/rot90"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:background="#FF000000"
+        android:orientation="vertical"
+        android:visibility="gone"
+        >
+
+        <!-- navigation controls -->
+        <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:src="@drawable/ic_sysbar_menu"
+            systemui:keyCode="82"
+            android:layout_weight="1"
+            />
+        <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:src="@drawable/ic_sysbar_home"
+            systemui:keyCode="3"
+            android:layout_weight="1"
+            />
+        <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:src="@drawable/ic_sysbar_back"
+            systemui:keyCode="4"
+            android:layout_weight="1"
+            />
+    </LinearLayout>
+
+    <LinearLayout android:id="@+id/rot270"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:background="#FF000000"
+        android:orientation="vertical"
+        android:visibility="gone"
+        >
+
+        <!-- navigation controls -->
+        <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:src="@drawable/ic_sysbar_back"
+            systemui:keyCode="4"
+            android:layout_weight="1"
+            />
+        <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:src="@drawable/ic_sysbar_home"
+            systemui:keyCode="3"
+            android:layout_weight="1"
+            />
+        <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:src="@drawable/ic_sysbar_menu"
+            systemui:keyCode="82"
+            android:layout_weight="1"
+            />
+    </LinearLayout>
+</com.android.systemui.statusbar.phone.NavigationBarView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 88d9739..8e456b2 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -1,24 +1,45 @@
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="65sp"
-    android:orientation="vertical"
+    android:layout_height="65dp"
     >
 
+    <ImageButton
+        android:id="@+id/veto"
+        android:layout_width="48dp"
+        android:layout_height="match_parent"
+        android:layout_centerVertical="true"
+        android:layout_alignParentRight="true"
+        android:src="@drawable/status_bar_veto"
+        android:scaleType="center"
+        android:background="@null"
+        android:paddingRight="8dp"
+        android:paddingLeft="8dp"
+        />
+
+    <ImageView
+        android:id="@+id/large_icon"
+        android:layout_width="@android:dimen/notification_large_icon_width"
+        android:layout_height="@android:dimen/notification_large_icon_height"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentLeft="true"
+        android:scaleType="center"
+        />
+
     <com.android.systemui.statusbar.LatestItemView android:id="@+id/content"
-            android:layout_width="match_parent"
-            android:layout_height="64sp"
-            android:background="@android:drawable/status_bar_item_background"
-            android:focusable="true"
-            android:clickable="true"
-            android:paddingRight="6sp"
-            >
-    </com.android.systemui.statusbar.LatestItemView>
+        android:layout_width="match_parent"
+        android:layout_height="64dp"
+        android:layout_alignParentTop="true"
+        android:layout_toRightOf="@id/large_icon"
+        android:layout_toLeftOf="@id/veto"
+        android:focusable="true"
+        android:clickable="true"
+        />
 
     <View
         android:layout_width="match_parent"
-        android:layout_height="1sp"
-        android:background="@android:drawable/divider_horizontal_bright"
+        android:layout_height="1dp"
+        android:layout_alignParentBottom="true"
+        android:background="@android:drawable/divider_horizontal_dark"
         />
 
-</LinearLayout>
-
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_tracking.xml b/packages/SystemUI/res/layout/status_bar_tracking.xml
index a0ddab5..baa45c5 100644
--- a/packages/SystemUI/res/layout/status_bar_tracking.xml
+++ b/packages/SystemUI/res/layout/status_bar_tracking.xml
@@ -26,11 +26,12 @@
     android:paddingRight="0px"
     >
 
-    <com.android.systemui.statusbar.phone.TrackingPatternView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_weight="1"
-        />
+    <View
+         android:layout_width="match_parent"
+         android:layout_height="wrap_content"
+         android:layout_weight="1"
+         android:background="#ff000000"
+         />
 
     <com.android.systemui.statusbar.phone.CloseDragHandle android:id="@+id/close"
         android:layout_width="match_parent"
@@ -42,7 +43,7 @@
             android:layout_height="wrap_content"
             android:layout_gravity="bottom"
             android:scaleType="fitXY"
-            android:src="@drawable/shade_handlebar"
+            android:src="@drawable/status_bar_close_on"
             />
 
     </com.android.systemui.statusbar.phone.CloseDragHandle>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
new file mode 100644
index 0000000..bcc8da1
--- /dev/null
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2011, 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.
+*/
+-->
+<resources>
+    <!-- thickness (width) of the navigation bar on phones that require it -->
+    <dimen name="navigation_bar_size">42dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 964e69b..9341693 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -20,4 +20,5 @@
     <drawable name="notification_number_text_color">#ffffffff</drawable>
     <drawable name="notification_item_background_color">#ff000000</drawable>
     <drawable name="ticker_background_color">#ff1d1d1d</drawable>
+    <drawable name="status_bar_background">#000000</drawable>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 88cd43c..a2577cb 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -31,5 +31,7 @@
     <!-- Width of scrollable area in recents -->
     <dimen name="status_bar_recents_width">356dp</dimen>
 
+    <!-- thickness (height) of the navigation bar on phones that require it -->
+    <dimen name="navigation_bar_size">42dp</dimen>
 </resources>
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
new file mode 100644
index 0000000..ec169e5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.Display;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.Surface;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.content.res.Configuration;
+
+import com.android.systemui.R;
+
+public class NavigationBarView extends LinearLayout {
+    final Display mDisplay;
+    View[] mRotatedViews = new View[4];
+
+    public NavigationBarView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mDisplay = ((WindowManager)context.getSystemService(
+                Context.WINDOW_SERVICE)).getDefaultDisplay();
+    }
+
+    public void onFinishInflate() {
+        mRotatedViews[Surface.ROTATION_0] = 
+        mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
+
+        mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90);
+        
+        mRotatedViews[Surface.ROTATION_270] = findViewById(R.id.rot270);
+    }
+
+    public void reorient() {
+        final int rot = mDisplay.getRotation();
+        for (int i=0; i<4; i++) {
+            mRotatedViews[i].setVisibility(View.GONE);
+        }
+        mRotatedViews[rot].setVisibility(View.VISIBLE);
+
+        android.util.Log.d("NavigationBarView", "reorient(): rot=" + mDisplay.getRotation());
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 1e46246..b4adde6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -45,6 +45,7 @@
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
+import android.view.Surface;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewGroup;
@@ -141,6 +142,9 @@
     // for immersive activities
     private View mIntruderAlertView;
 
+    // on-screen navigation buttons
+    private NavigationBarView mNavigationBarView;
+
     // the tracker view
     TrackingView mTrackingView;
     WindowManager.LayoutParams mTrackingParams;
@@ -199,7 +203,9 @@
 
         super.start();
 
-        addIntruderView();
+        addNavigationBar();
+
+        //addIntruderView();
 
         // Lastly, call to the icon policy to install/update all the icons.
         mIconPolicy = new PhoneStatusBarPolicy(mContext);
@@ -223,6 +229,9 @@
         mIntruderAlertView.setVisibility(View.GONE);
         mIntruderAlertView.setClickable(true);
 
+        mNavigationBarView = 
+            (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
+
         PhoneStatusBarView sb = (PhoneStatusBarView)View.inflate(context,
                 R.layout.status_bar, null);
         sb.mService = this;
@@ -292,6 +301,58 @@
         return res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
     }
 
+    // For small-screen devices (read: phones) that lack hardware navigation buttons
+    private void addNavigationBar() {
+        mNavigationBarView.reorient();
+        WindowManagerImpl.getDefault().addView(
+                mNavigationBarView, getNavigationBarLayoutParams());
+    }
+
+    private void repositionNavigationBar() {
+        mNavigationBarView.reorient();
+        WindowManagerImpl.getDefault().updateViewLayout(
+                mNavigationBarView, getNavigationBarLayoutParams());
+    }
+
+    private WindowManager.LayoutParams getNavigationBarLayoutParams() {
+        final int rotation = mDisplay.getRotation();
+        final boolean sideways = 
+            (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270);
+
+        final Resources res = mContext.getResources();
+        final int size = res.getDimensionPixelSize(R.dimen.navigation_bar_size);
+
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                sideways ? size : ViewGroup.LayoutParams.MATCH_PARENT,
+                sideways ? ViewGroup.LayoutParams.MATCH_PARENT : size,
+                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
+                    0
+                    | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                    | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                    | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
+                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+                PixelFormat.TRANSLUCENT);
+
+        lp.setTitle("NavigationBar");
+        switch (rotation) {
+            case Surface.ROTATION_90:
+                // device has been turned 90deg counter-clockwise
+                lp.gravity = Gravity.RIGHT | Gravity.FILL_VERTICAL;
+                break;
+            case Surface.ROTATION_270:
+                // device has been turned 90deg clockwise
+                lp.gravity = Gravity.LEFT | Gravity.FILL_VERTICAL;
+                break;
+            default:
+                lp.gravity = Gravity.BOTTOM | Gravity.FILL_HORIZONTAL;
+                break;
+        }
+        lp.windowAnimations = 0;
+
+        return lp;
+    }
+
     private void addIntruderView() {
         final int height = getStatusBarHeight();
 
@@ -511,6 +572,38 @@
                 Context.LAYOUT_INFLATER_SERVICE);
         View row = inflater.inflate(R.layout.status_bar_notification_row, parent, false);
 
+        // wire up the veto button
+        View vetoButton = row.findViewById(R.id.veto);
+        if (notification.isClearable()) {
+            final String _pkg = notification.pkg;
+            final String _tag = notification.tag;
+            final int _id = notification.id;
+            vetoButton.setOnClickListener(new View.OnClickListener() {
+                    public void onClick(View v) {
+                        try {
+                            mBarService.onNotificationClear(_pkg, _tag, _id);
+                        } catch (RemoteException ex) {
+                            // system process is dead if we're here.
+                        }
+                    }
+                });
+        } else {
+            if ((notification.notification.flags & Notification.FLAG_ONGOING_EVENT) == 0) {
+                vetoButton.setVisibility(View.INVISIBLE);
+            } else {
+                vetoButton.setVisibility(View.GONE);
+            }
+        }
+
+        // the large icon
+        ImageView largeIcon = (ImageView)row.findViewById(R.id.large_icon);
+        if (notification.notification.largeIcon != null) {
+            largeIcon.setImageBitmap(notification.notification.largeIcon);
+        } else {
+            largeIcon.getLayoutParams().width = 0;
+            largeIcon.setVisibility(View.INVISIBLE);
+        }
+
         // bind the click event to the content area
         ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
         content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
@@ -1497,6 +1590,7 @@
                 animateCollapse();
             }
             else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
+                repositionNavigationBar();
                 updateResources();
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java
index 90c9568..9924faa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java
@@ -77,7 +77,9 @@
         if (plugged) {
             final DisplayMetrics metrics = new DisplayMetrics();
             mWindowManager.getDefaultDisplay().getMetrics(metrics);
-            height = metrics.heightPixels - 720;
+            //Slog.i(TAG, "setPlugged: display metrics=" + metrics);
+            final int shortSide = Math.min(metrics.widthPixels, metrics.heightPixels);
+            height = shortSide - 720;
         }
 
         final int minHeight
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 27b7e1c..d997109 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -28,17 +28,15 @@
 
 import com.android.internal.view.RootViewSurfaceTaker;
 import com.android.internal.view.StandaloneActionMode;
-import com.android.internal.view.menu.ActionMenuView;
 import com.android.internal.view.menu.ContextMenuBuilder;
-import com.android.internal.view.menu.ListMenuPresenter;
 import com.android.internal.view.menu.IconMenuPresenter;
+import com.android.internal.view.menu.ListMenuPresenter;
 import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.view.menu.MenuDialogHelper;
-import com.android.internal.view.menu.MenuItemImpl;
-import com.android.internal.view.menu.MenuPopupHelper;
-import com.android.internal.view.menu.MenuView;
 import com.android.internal.view.menu.MenuPresenter;
+import com.android.internal.view.menu.MenuView;
 import com.android.internal.view.menu.SubMenuBuilder;
+import com.android.internal.widget.ActionBarContainer;
 import com.android.internal.widget.ActionBarContextView;
 import com.android.internal.widget.ActionBarView;
 
@@ -625,7 +623,7 @@
         }
     }
 
-    private void checkCloseActionMenu(Menu menu) {
+    void checkCloseActionMenu(Menu menu) {
         if (mClosingActionMenu) {
             return;
         }
@@ -882,7 +880,7 @@
                     final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
                     if (cb.onPreparePanel(FEATURE_OPTIONS_PANEL, st.createdPanelView, st.menu)) {
                         cb.onMenuOpened(FEATURE_ACTION_BAR, st.menu);
-                        mActionBar.openOverflowMenu();
+                        mActionBar.showOverflowMenu();
                     }
                 }
             } else {
@@ -1526,6 +1524,7 @@
             }
 
             st.onRestoreInstanceState(icicles.get(curFeatureId));
+            invalidatePanelMenu(curFeatureId);
         }
 
         /*
@@ -1964,8 +1963,13 @@
                 mContextMenu.clearAll();
             }
 
-            mContextMenuHelper = mContextMenu.show(originalView, originalView.getWindowToken());
-            return mContextMenuHelper != null;
+            final MenuDialogHelper helper = mContextMenu.show(originalView,
+                    originalView.getWindowToken());
+            if (helper != null) {
+                helper.setPresenterCallback(mContextMenuCallback);
+            }
+            mContextMenuHelper = helper;
+            return helper != null;
         }
 
         @Override
@@ -2591,11 +2595,16 @@
                     final boolean splitActionBar = getWindowStyle().getBoolean(
                             com.android.internal.R.styleable.Window_windowSplitActionBar, false);
                     if (splitActionBar) {
-                        final ViewGroup splitView = (ViewGroup) findViewById(
-                                com.android.internal.R.id.lower_action_context_bar);
+                        final ActionBarContainer splitView = (ActionBarContainer) findViewById(
+                                com.android.internal.R.id.split_action_bar);
                         if (splitView != null) {
+                            splitView.setVisibility(View.VISIBLE);
                             mActionBar.setSplitActionBar(splitActionBar);
                             mActionBar.setSplitView(splitView);
+
+                            final ActionBarContextView cab = (ActionBarContextView) findViewById(
+                                    com.android.internal.R.id.action_context_bar);
+                            cab.setSplitView(splitView);
                         } else {
                             Log.e(TAG, "Window style requested split action bar with " +
                                     "incompatible window decor! Ignoring request.");
@@ -3107,9 +3116,8 @@
              * The first time the menu is being shown after restoring, the
              * Activity.onCreateOptionsMenu should be called. But, if it is the
              * same instance then menu != null and we won't call that method.
-             * So, clear this.  Also clear any cached views.
+             * We clear any cached views here. The caller should invalidatePanelMenu.
              */
-            menu = null;
             createdPanelView = null;
             shownPanelView = null;
             decorView = null;
@@ -3168,7 +3176,7 @@
      * <li> Calls back to the callback's onMenuItemSelected when an item is
      * selected.
      */
-    private final class DialogMenuCallback implements MenuBuilder.Callback {
+    private final class DialogMenuCallback implements MenuBuilder.Callback, MenuPresenter.Callback {
         private int mFeatureId;
         private MenuDialogHelper mSubMenuHelper;
 
@@ -3177,6 +3185,10 @@
         }
 
         public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+            if (menu.getRootMenu() != menu) {
+                onCloseSubMenu(menu);
+            }
+
             if (allMenusAreClosing) {
                 Callback callback = getCallback();
                 if (callback != null && !isDestroyed()) {
@@ -3195,7 +3207,7 @@
             }
         }
 
-        public void onCloseSubMenu(SubMenuBuilder menu) {
+        public void onCloseSubMenu(MenuBuilder menu) {
             Callback callback = getCallback();
             if (callback != null && !isDestroyed()) {
                 callback.onPanelClosed(mFeatureId, menu.getRootMenu());
@@ -3211,7 +3223,7 @@
         public void onMenuModeChange(MenuBuilder menu) {
         }
 
-        public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
+        public boolean onOpenSubMenu(MenuBuilder subMenu) {
             // Set a simple callback for the submenu
             subMenu.setCallback(this);
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index a37ccc7..6632f34 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -111,6 +111,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import android.view.WindowManagerImpl;
 import android.view.WindowManagerPolicy;
 import android.view.KeyCharacterMap.FallbackAction;
@@ -175,14 +176,16 @@
     // responsible for power management when displayed.
     static final int KEYGUARD_LAYER = 15;
     static final int KEYGUARD_DIALOG_LAYER = 16;
+    // the navigation bar, if available, shows atop most things
+    static final int NAVIGATION_BAR_LAYER = 17;
     // the drag layer: input for drag-and-drop is associated with this window,
     // which sits above all other focusable windows
-    static final int DRAG_LAYER = 17;
+    static final int DRAG_LAYER = 18;
     // things in here CAN NOT take focus, but are shown on top of everything else.
-    static final int SYSTEM_OVERLAY_LAYER = 18;
-    static final int SECURE_SYSTEM_OVERLAY_LAYER = 19;
+    static final int SYSTEM_OVERLAY_LAYER = 19;
+    static final int SECURE_SYSTEM_OVERLAY_LAYER = 20;
     // the (mouse) pointer layer
-    static final int POINTER_LAYER = 20;
+    static final int POINTER_LAYER = 21;
 
     static final int APPLICATION_MEDIA_SUBLAYER = -2;
     static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
@@ -228,6 +231,8 @@
     WindowState mStatusBar = null;
     boolean mStatusBarCanHide;
     final ArrayList<WindowState> mStatusBarPanels = new ArrayList<WindowState>();
+    WindowState mNavigationBar = null;
+
     WindowState mKeyguard = null;
     KeyguardViewMediator mKeyguardMediator;
     GlobalActions mGlobalActions;
@@ -1037,6 +1042,8 @@
             return DRAG_LAYER;
         case TYPE_POINTER:
             return POINTER_LAYER;
+        case TYPE_NAVIGATION_BAR:
+            return NAVIGATION_BAR_LAYER;
         }
         Log.e(TAG, "Unknown window type: " + type);
         return APPLICATION_LAYER;
@@ -1214,6 +1221,13 @@
                         com.android.internal.R.bool.config_statusBarCanHide);
 
                 break;
+            case TYPE_NAVIGATION_BAR:
+                mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.STATUS_BAR_SERVICE,
+                        "PhoneWindowManager");
+                mNavigationBar = win;
+                if (DEBUG_LAYOUT) Log.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
+                break;
             case TYPE_STATUS_BAR_PANEL:
                 mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.STATUS_BAR_SERVICE,
@@ -1240,9 +1254,10 @@
     public void removeWindowLw(WindowState win) {
         if (mStatusBar == win) {
             mStatusBar = null;
-        }
-        else if (mKeyguard == win) {
+        } else if (mKeyguard == win) {
             mKeyguard = null;
+        } else if (mNavigationBar == win) {
+            mNavigationBar = null;
         } else {
             mStatusBarPanels.remove(win);
         }
@@ -1609,17 +1624,48 @@
         mDockBottom = mContentBottom = mCurBottom = displayHeight;
         mDockLayer = 0x10000000;
 
+        // start with the current dock rect, which will be (0,0,displayWidth,displayHeight)
+        final Rect pf = mTmpParentFrame;
+        final Rect df = mTmpDisplayFrame;
+        final Rect vf = mTmpVisibleFrame;
+        pf.left = df.left = vf.left = mDockLeft;
+        pf.top = df.top = vf.top = mDockTop;
+        pf.right = df.right = vf.right = mDockRight;
+        pf.bottom = df.bottom = vf.bottom = mDockBottom;
+
         // decide where the status bar goes ahead of time
         if (mStatusBar != null) {
-            final Rect pf = mTmpParentFrame;
-            final Rect df = mTmpDisplayFrame;
-            final Rect vf = mTmpVisibleFrame;
-            pf.left = df.left = vf.left = 0;
-            pf.top = df.top = vf.top = 0;
-            pf.right = df.right = vf.right = displayWidth;
-            pf.bottom = df.bottom = vf.bottom = displayHeight;
-            
+            Rect navr = null;
+            if (mNavigationBar != null) {
+                mNavigationBar.computeFrameLw(pf, df, vf, vf);
+                if (mNavigationBar.isVisibleLw()) {
+                    navr = mNavigationBar.getFrameLw();
+
+                    if (navr.top == 0) {
+                        // Navigation bar is vertical
+                        if (mDockLeft == navr.left) {
+                            mDockLeft = navr.right;
+                        } else if (mDockRight == navr.right) {
+                            mDockRight = navr.left;
+                        }
+                    } else {
+                        // Navigation bar horizontal, at bottom
+                        if (mDockBottom == navr.bottom) {
+                            mDockBottom = navr.top;
+                        }
+                    }
+                }
+            }
+            if (DEBUG_LAYOUT) Log.i(TAG, "mNavigationBar frame: " + navr);
+
+            // apply navigation bar insets
+            pf.left = df.left = vf.left = mDockLeft;
+            pf.top = df.top = vf.top = mDockTop;
+            pf.right = df.right = vf.right = mDockRight;
+            pf.bottom = df.bottom = vf.bottom = mDockBottom;
+
             mStatusBar.computeFrameLw(pf, df, vf, vf);
+
             if (mStatusBar.isVisibleLw()) {
                 // If the status bar is hidden, we don't want to cause
                 // windows behind it to scroll.
@@ -1630,14 +1676,18 @@
                     // status bar is visible.
                     if (mDockTop == r.top) mDockTop = r.bottom;
                     else if (mDockBottom == r.bottom) mDockBottom = r.top;
+                    
                     mContentTop = mCurTop = mDockTop;
                     mContentBottom = mCurBottom = mDockBottom;
-                    if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: mDockTop=" + mDockTop
-                            + " mContentTop=" + mContentTop
-                            + " mCurTop=" + mCurTop
-                            + " mDockBottom=" + mDockBottom
-                            + " mContentBottom=" + mContentBottom
-                            + " mCurBottom=" + mCurBottom);
+                    mContentLeft = mCurLeft = mDockLeft;
+                    mContentRight = mCurRight = mDockRight;
+
+                    if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: " +
+                        String.format(
+                            "dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]",
+                            mDockLeft, mDockTop, mDockRight, mDockBottom,
+                            mContentLeft, mContentTop, mContentRight, mContentBottom,
+                            mCurLeft, mCurTop, mCurRight, mCurBottom));
                 } else {
                     // Status bar can't go away; the part of the screen it
                     // covers does not exist for anything behind it.
@@ -1647,12 +1697,32 @@
                     } else if ((mRestrictedScreenHeight-mRestrictedScreenTop) == r.bottom) {
                         mRestrictedScreenHeight -= (r.bottom-r.top);
                     }
+
+                    if (navr != null) {
+                        if (navr.top == 0) {
+                            // Navigation bar is vertical
+                            if (mRestrictedScreenLeft == navr.left) {
+                                mRestrictedScreenLeft = navr.right;
+                                mRestrictedScreenWidth -= (navr.right - navr.left);
+                            } else if ((mRestrictedScreenLeft+mRestrictedScreenWidth) == navr.right) {
+                                mRestrictedScreenWidth -= (navr.right - navr.left);
+                            }
+                        } else {
+                            // Navigation bar horizontal, at bottom
+                            if ((mRestrictedScreenHeight-mRestrictedScreenTop) == r.bottom) {
+                                mRestrictedScreenHeight -= (navr.bottom-navr.top);
+                            }
+                        }
+                    }
+
                     mContentTop = mCurTop = mDockTop = mRestrictedScreenTop;
                     mContentBottom = mCurBottom = mDockBottom
                             = mRestrictedScreenTop + mRestrictedScreenHeight;
-                    if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: mRestrictedScreenTop="
-                            + mRestrictedScreenTop
-                            + " mRestrictedScreenHeight=" + mRestrictedScreenHeight);
+                    if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: restricted screen area: ("
+                            + mRestrictedScreenLeft + ","
+                            + mRestrictedScreenTop + ","
+                            + (mRestrictedScreenLeft + mRestrictedScreenWidth) + ","
+                            + (mRestrictedScreenTop + mRestrictedScreenHeight) + ")");
                 }
             }
         }
@@ -1722,6 +1792,8 @@
         final Rect cf = mTmpContentFrame;
         final Rect vf = mTmpVisibleFrame;
         
+        final boolean hasNavBar = (mNavigationBar != null && mNavigationBar.isVisibleLw());
+
         if (attrs.type == TYPE_INPUT_METHOD) {
             pf.left = df.left = cf.left = vf.left = mDockLeft;
             pf.top = df.top = cf.top = vf.top = mDockTop;
@@ -1735,6 +1807,9 @@
 
             if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
                     == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
+                if (DEBUG_LAYOUT)
+                    Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() 
+                            + "): IN_SCREEN, INSET_DECOR, !FULLSCREEN");
                 // This is the case for a normal activity window: we want it
                 // to cover all of the screen space, and it can take care of
                 // moving its contents to account for screen decorations that
@@ -1744,15 +1819,26 @@
                     // frame is the same as the one we are attached to.
                     setAttachedWindowFrames(win, fl, sim, attached, true, pf, df, cf, vf);
                 } else {
-                    if (attrs.type == TYPE_STATUS_BAR_PANEL) {
+                    if (attrs.type == TYPE_STATUS_BAR_PANEL
+                            || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
                         // Status bar panels are the only windows who can go on top of
                         // the status bar.  They are protected by the STATUS_BAR_SERVICE
                         // permission, so they have the same privileges as the status
                         // bar itself.
-                        pf.left = df.left = mUnrestrictedScreenLeft;
+                        //
+                        // However, they should still dodge the navigation bar if it exists. A
+                        // straightforward way to do this is to only allow the status bar panels to
+                        // extend to the extrema of the allowable region for the IME dock.
+
+                        pf.left = df.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft;
                         pf.top = df.top = mUnrestrictedScreenTop;
-                        pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
-                        pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+                        pf.right = df.right = hasNavBar
+                                            ? mDockRight
+                                            : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+                        pf.bottom = df.bottom = hasNavBar
+                                              ? mDockBottom
+                                              : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+
                     } else {
                         pf.left = df.left = mRestrictedScreenLeft;
                         pf.top = df.top = mRestrictedScreenTop;
@@ -1780,15 +1866,21 @@
                     }
                 }
             } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0) {
+                if (DEBUG_LAYOUT)
+                    Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): IN_SCREEN");
                 // A window that has requested to fill the entire screen just
                 // gets everything, period.
-                if (attrs.type == TYPE_STATUS_BAR_PANEL) {
-                    pf.left = df.left = cf.left = mUnrestrictedScreenLeft;
+                if (attrs.type == TYPE_STATUS_BAR_PANEL
+                        || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
+                    pf.left = df.left = cf.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft;
                     pf.top = df.top = cf.top = mUnrestrictedScreenTop;
-                    pf.right = df.right = cf.right
-                            = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
-                    pf.bottom = df.bottom = cf.bottom
-                            = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+                    pf.right = df.right = cf.right = hasNavBar
+                                        ? mDockRight
+                                        : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+                    pf.bottom = df.bottom = cf.bottom = hasNavBar
+                                          ? mDockBottom
+                                          : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+
                 } else {
                     pf.left = df.left = cf.left = mRestrictedScreenLeft;
                     pf.top = df.top = cf.top = mRestrictedScreenTop;
@@ -1805,10 +1897,14 @@
                     vf.set(cf);
                 }
             } else if (attached != null) {
+                if (DEBUG_LAYOUT)
+                    Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): attached to " + attached);
                 // A child window should be placed inside of the same visible
                 // frame that its parent had.
                 setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf);
             } else {
+                if (DEBUG_LAYOUT)
+                    Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): normal window");
                 // Otherwise, a normal window must be placed inside the content
                 // of all screen decorations.
                 pf.left = mContentLeft;
@@ -1844,6 +1940,8 @@
 
         if (DEBUG_LAYOUT) Log.v(TAG, "Compute frame " + attrs.getTitle()
                 + ": sim=#" + Integer.toHexString(sim)
+                + " attach=" + attached + " type=" + attrs.type 
+                + String.format(" flags=0x%08x", fl)
                 + " pf=" + pf.toShortString() + " df=" + df.toShortString()
                 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString());
         
@@ -2119,11 +2217,11 @@
     }
 
     void initializeHdmiState() {
+        boolean plugged = false;
         // watch for HDMI plug messages if the hdmi switch exists
         if (new File("/sys/devices/virtual/switch/hdmi/state").exists()) {
             mHDMIObserver.startObserving("DEVPATH=/devices/virtual/switch/hdmi");
 
-            boolean plugged = false;
             final String filename = "/sys/class/switch/hdmi/state";
             FileReader reader = null;
             try {
@@ -2145,11 +2243,11 @@
                     }
                 }
             }
-
-            // This dance forces the code in setHdmiPlugged to run.
-            mHdmiPlugged = !plugged;
-            setHdmiPlugged(!mHdmiPlugged);
         }
+        // This dance forces the code in setHdmiPlugged to run.
+        // Always do this so the sticky intent is stuck (to false) if there is no hdmi.
+        mHdmiPlugged = !plugged;
+        setHdmiPlugged(!mHdmiPlugged);
     }
 
     /**
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 14f1e8b..e35435e 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -1,38 +1,5 @@
 LOCAL_PATH:= $(call my-dir)
 
-# Set USE_CAMERA_STUB if you don't want to use the hardware camera.
-
-# force these builds to use camera stub only
-ifneq ($(filter sooner generic sim,$(TARGET_DEVICE)),)
-  USE_CAMERA_STUB:=true
-endif
-
-ifeq ($(USE_CAMERA_STUB),)
-  USE_CAMERA_STUB:=false
-endif
-
-ifeq ($(USE_CAMERA_STUB),true)
-#
-# libcamerastub
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:=               \
-    CameraHardwareStub.cpp      \
-    FakeCamera.cpp
-
-LOCAL_MODULE:= libcamerastub
-
-ifeq ($(TARGET_SIMULATOR),true)
-LOCAL_CFLAGS += -DSINGLE_PROCESS
-endif
-
-LOCAL_SHARED_LIBRARIES:= libui
-
-include $(BUILD_STATIC_LIBRARY)
-endif # USE_CAMERA_STUB
-
 #
 # libcameraservice
 #
@@ -49,18 +16,9 @@
     libcutils \
     libmedia \
     libcamera_client \
-    libgui
+    libgui \
+    libhardware
 
 LOCAL_MODULE:= libcameraservice
 
-ifeq ($(TARGET_SIMULATOR),true)
-LOCAL_CFLAGS += -DSINGLE_PROCESS
-endif
-
-ifeq ($(USE_CAMERA_STUB), true)
-LOCAL_STATIC_LIBRARIES += libcamerastub
-else
-LOCAL_SHARED_LIBRARIES += libcamera 
-endif
-
 include $(BUILD_SHARED_LIBRARY)
diff --git a/services/camera/libcameraservice/CameraHardwareInterface.h b/services/camera/libcameraservice/CameraHardwareInterface.h
new file mode 100644
index 0000000..f9fa30e
--- /dev/null
+++ b/services/camera/libcameraservice/CameraHardwareInterface.h
@@ -0,0 +1,619 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
+#define ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
+
+#include <binder/IMemory.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
+#include <utils/RefBase.h>
+#include <surfaceflinger/ISurface.h>
+#include <ui/android_native_buffer.h>
+#include <ui/GraphicBuffer.h>
+#include <camera/Camera.h>
+#include <camera/CameraParameters.h>
+#include <system/window.h>
+#include <hardware/camera.h>
+
+namespace android {
+
+typedef void (*notify_callback)(int32_t msgType,
+                            int32_t ext1,
+                            int32_t ext2,
+                            void* user);
+
+typedef void (*data_callback)(int32_t msgType,
+                            const sp<IMemory> &dataPtr,
+                            void* user);
+
+typedef void (*data_callback_timestamp)(nsecs_t timestamp,
+                            int32_t msgType,
+                            const sp<IMemory> &dataPtr,
+                            void *user);
+
+/**
+ * CameraHardwareInterface.h defines the interface to the
+ * camera hardware abstraction layer, used for setting and getting
+ * parameters, live previewing, and taking pictures.
+ *
+ * It is a referenced counted interface with RefBase as its base class.
+ * CameraService calls openCameraHardware() to retrieve a strong pointer to the
+ * instance of this interface and may be called multiple times. The
+ * following steps describe a typical sequence:
+ *
+ *   -# After CameraService calls openCameraHardware(), getParameters() and
+ *      setParameters() are used to initialize the camera instance.
+ *      CameraService calls getPreviewHeap() to establish access to the
+ *      preview heap so it can be registered with SurfaceFlinger for
+ *      efficient display updating while in preview mode.
+ *   -# startPreview() is called.  The camera instance then periodically
+ *      sends the message CAMERA_MSG_PREVIEW_FRAME (if enabled) each time
+ *      a new preview frame is available.  If data callback code needs to use
+ *      this memory after returning, it must copy the data.
+ *
+ * Prior to taking a picture, CameraService calls autofocus(). When auto
+ * focusing has completed, the camera instance sends a CAMERA_MSG_FOCUS notification,
+ * which informs the application whether focusing was successful. The camera instance
+ * only sends this message once and it is up  to the application to call autoFocus()
+ * again if refocusing is desired.
+ *
+ * CameraService calls takePicture() to request the camera instance take a
+ * picture. At this point, if a shutter, postview, raw, and/or compressed callback
+ * is desired, the corresponding message must be enabled. As with CAMERA_MSG_PREVIEW_FRAME,
+ * any memory provided in a data callback must be copied if it's needed after returning.
+ */
+
+class CameraHardwareInterface : public virtual RefBase {
+public:
+    CameraHardwareInterface(hw_module_t *module, const char *name)
+    {
+        mDevice = 0;
+        mName = name;
+        LOGI("Opening camera %s, this %p", name, this);
+        int rc = module->methods->open(module, name,
+                                       (hw_device_t **)&mDevice);
+        if (rc != OK)
+            LOGE("Could not open camera %s: %d", name, rc);
+        initHalPreviewWindow();
+    }
+
+    ~CameraHardwareInterface()
+    {
+        LOGI("Destroying camera %s", mName.string());
+        int rc = mDevice->common.close(&mDevice->common);
+        if (rc != OK)
+            LOGE("Could not close camera %s: %d", mName.string(), rc);
+    }
+
+    /** Set the ANativeWindow to which preview frames are sent */
+    status_t setPreviewWindow(const sp<ANativeWindow>& buf)
+    {
+        LOGV("%s(%s) buf %p", __FUNCTION__, mName.string(), buf.get());
+
+        if (mDevice->ops->set_preview_window) {
+            mPreviewWindow = buf;
+            mHalPreviewWindow.user = this;
+            LOGV("%s &mHalPreviewWindow %p mHalPreviewWindow.user %p", __FUNCTION__,
+                    &mHalPreviewWindow, mHalPreviewWindow.user);
+            return mDevice->ops->set_preview_window(mDevice,
+                    buf.get() ? &mHalPreviewWindow.nw : 0);
+        }
+        return INVALID_OPERATION;
+    }
+
+    /** Set the notification and data callbacks */
+    void setCallbacks(notify_callback notify_cb,
+                      data_callback data_cb,
+                      data_callback_timestamp data_cb_timestamp,
+                      void* user)
+    {
+        mNotifyCb = notify_cb;
+        mDataCb = data_cb;
+        mDataCbTimestamp = data_cb_timestamp;
+        mCbUser = user;
+
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+
+        if (mDevice->ops->set_callbacks) {
+            mDevice->ops->set_callbacks(mDevice,
+                                   __notify_cb,
+                                   __data_cb,
+                                   __data_cb_timestamp,
+                                   __get_memory,
+                                   this);
+        }
+    }
+
+    /**
+     * The following three functions all take a msgtype,
+     * which is a bitmask of the messages defined in
+     * include/ui/Camera.h
+     */
+
+    /**
+     * Enable a message, or set of messages.
+     */
+    void enableMsgType(int32_t msgType)
+    {
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+        if (mDevice->ops->enable_msg_type)
+            mDevice->ops->enable_msg_type(mDevice, msgType);
+    }
+
+    /**
+     * Disable a message, or a set of messages.
+     *
+     * Once received a call to disableMsgType(CAMERA_MSG_VIDEO_FRAME), camera hal
+     * should not rely on its client to call releaseRecordingFrame() to release
+     * video recording frames sent out by the cameral hal before and after the
+     * disableMsgType(CAMERA_MSG_VIDEO_FRAME) call. Camera hal clients must not
+     * modify/access any video recording frame after calling
+     * disableMsgType(CAMERA_MSG_VIDEO_FRAME).
+     */
+    void disableMsgType(int32_t msgType)
+    {
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+        if (mDevice->ops->disable_msg_type)
+            mDevice->ops->disable_msg_type(mDevice, msgType);
+    }
+
+    /**
+     * Query whether a message, or a set of messages, is enabled.
+     * Note that this is operates as an AND, if any of the messages
+     * queried are off, this will return false.
+     */
+    int msgTypeEnabled(int32_t msgType)
+    {
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+        if (mDevice->ops->msg_type_enabled)
+            return mDevice->ops->msg_type_enabled(mDevice, msgType);
+        return false;
+    }
+
+    /**
+     * Start preview mode.
+     */
+    status_t startPreview()
+    {
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+        if (mDevice->ops->start_preview)
+            return mDevice->ops->start_preview(mDevice);
+        return INVALID_OPERATION;
+    }
+
+    /**
+     * Stop a previously started preview.
+     */
+    void stopPreview()
+    {
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+        if (mDevice->ops->stop_preview)
+            mDevice->ops->stop_preview(mDevice);
+    }
+
+    /**
+     * Returns true if preview is enabled.
+     */
+    int previewEnabled()
+    {
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+        if (mDevice->ops->preview_enabled)
+            return mDevice->ops->preview_enabled(mDevice);
+        return false;
+    }
+
+    /**
+     * Request the camera hal to store meta data or real YUV data in
+     * the video buffers send out via CAMERA_MSG_VIDEO_FRRAME for a
+     * recording session. If it is not called, the default camera
+     * hal behavior is to store real YUV data in the video buffers.
+     *
+     * This method should be called before startRecording() in order
+     * to be effective.
+     *
+     * If meta data is stored in the video buffers, it is up to the
+     * receiver of the video buffers to interpret the contents and
+     * to find the actual frame data with the help of the meta data
+     * in the buffer. How this is done is outside of the scope of
+     * this method.
+     *
+     * Some camera hal may not support storing meta data in the video
+     * buffers, but all camera hal should support storing real YUV data
+     * in the video buffers. If the camera hal does not support storing
+     * the meta data in the video buffers when it is requested to do
+     * do, INVALID_OPERATION must be returned. It is very useful for
+     * the camera hal to pass meta data rather than the actual frame
+     * data directly to the video encoder, since the amount of the
+     * uncompressed frame data can be very large if video size is large.
+     *
+     * @param enable if true to instruct the camera hal to store
+     *      meta data in the video buffers; false to instruct
+     *      the camera hal to store real YUV data in the video
+     *      buffers.
+     *
+     * @return OK on success.
+     */
+
+    status_t storeMetaDataInBuffers(int enable)
+    {
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+        if (mDevice->ops->store_meta_data_in_buffers)
+            return mDevice->ops->store_meta_data_in_buffers(mDevice, enable);
+        return enable ? INVALID_OPERATION: OK;
+    }
+
+    /**
+     * Start record mode. When a record image is available a CAMERA_MSG_VIDEO_FRAME
+     * message is sent with the corresponding frame. Every record frame must be released
+     * by a cameral hal client via releaseRecordingFrame() before the client calls
+     * disableMsgType(CAMERA_MSG_VIDEO_FRAME). After the client calls
+     * disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is camera hal's responsibility
+     * to manage the life-cycle of the video recording frames, and the client must
+     * not modify/access any video recording frames.
+     */
+    status_t startRecording()
+    {
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+        if (mDevice->ops->start_recording)
+            return mDevice->ops->start_recording(mDevice);
+        return INVALID_OPERATION;
+    }
+
+    /**
+     * Stop a previously started recording.
+     */
+    void stopRecording()
+    {
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+        if (mDevice->ops->stop_recording)
+            mDevice->ops->stop_recording(mDevice);
+    }
+
+    /**
+     * Returns true if recording is enabled.
+     */
+    int recordingEnabled()
+    {
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+        if (mDevice->ops->recording_enabled)
+            return mDevice->ops->recording_enabled(mDevice);
+        return false;
+    }
+
+    /**
+     * Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME.
+     *
+     * It is camera hal client's responsibility to release video recording
+     * frames sent out by the camera hal before the camera hal receives
+     * a call to disableMsgType(CAMERA_MSG_VIDEO_FRAME). After it receives
+     * the call to disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is camera hal's
+     * responsibility of managing the life-cycle of the video recording
+     * frames.
+     */
+    void releaseRecordingFrame(const sp<IMemory>& mem)
+    {
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+        if (mDevice->ops->release_recording_frame) {
+            ssize_t offset;
+            size_t size;
+            sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+            void *data = ((uint8_t *)heap->base()) + offset;
+            return mDevice->ops->release_recording_frame(mDevice, data);
+        }
+    }
+
+    /**
+     * Start auto focus, the notification callback routine is called
+     * with CAMERA_MSG_FOCUS once when focusing is complete. autoFocus()
+     * will be called again if another auto focus is needed.
+     */
+    status_t autoFocus()
+    {
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+        if (mDevice->ops->auto_focus)
+            return mDevice->ops->auto_focus(mDevice);
+        return INVALID_OPERATION;
+    }
+
+    /**
+     * Cancels auto-focus function. If the auto-focus is still in progress,
+     * this function will cancel it. Whether the auto-focus is in progress
+     * or not, this function will return the focus position to the default.
+     * If the camera does not support auto-focus, this is a no-op.
+     */
+    status_t cancelAutoFocus()
+    {
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+        if (mDevice->ops->cancel_auto_focus)
+            return mDevice->ops->cancel_auto_focus(mDevice);
+        return INVALID_OPERATION;
+    }
+
+    /**
+     * Take a picture.
+     */
+    status_t takePicture()
+    {
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+        if (mDevice->ops->take_picture)
+            return mDevice->ops->take_picture(mDevice);
+        return INVALID_OPERATION;
+    }
+
+    /**
+     * Cancel a picture that was started with takePicture.  Calling this
+     * method when no picture is being taken is a no-op.
+     */
+    status_t cancelPicture()
+    {
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+        if (mDevice->ops->cancel_picture)
+            return mDevice->ops->cancel_picture(mDevice);
+        return INVALID_OPERATION;
+    }
+
+    /**
+     * Set the camera parameters. This returns BAD_VALUE if any parameter is
+     * invalid or not supported. */
+    status_t setParameters(const CameraParameters &params)
+    {
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+        if (mDevice->ops->set_parameters)
+            return mDevice->ops->set_parameters(mDevice,
+                                               params.flatten().string());
+        return INVALID_OPERATION;
+    }
+
+    /** Return the camera parameters. */
+    CameraParameters getParameters() const
+    {
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+        CameraParameters parms;
+        if (mDevice->ops->get_parameters) {
+            char *temp = mDevice->ops->get_parameters(mDevice);
+            String8 str_parms(temp);
+            free(temp);
+            parms.unflatten(str_parms);
+        }
+        return parms;
+    }
+
+    /**
+     * Send command to camera driver.
+     */
+    status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
+    {
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+        if (mDevice->ops->send_command)
+            return mDevice->ops->send_command(mDevice, cmd, arg1, arg2);
+        return INVALID_OPERATION;
+    }
+
+    /**
+     * Release the hardware resources owned by this object.  Note that this is
+     * *not* done in the destructor.
+     */
+    void release() {
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+        if (mDevice->ops->release)
+            mDevice->ops->release(mDevice);
+    }
+
+    /**
+     * Dump state of the camera hardware
+     */
+    status_t dump(int fd, const Vector<String16>& args) const
+    {
+        LOGV("%s(%s)", __FUNCTION__, mName.string());
+        if (mDevice->ops->dump)
+            return mDevice->ops->dump(mDevice, fd);
+        return OK; // It's fine if the HAL doesn't implement dump()
+    }
+
+private:
+    camera_device_t *mDevice;
+    String8 mName;
+
+    static void __notify_cb(int32_t msg_type, int32_t ext1,
+                            int32_t ext2, void *user)
+    {
+        LOGV("%s", __FUNCTION__);
+        CameraHardwareInterface *__this =
+                static_cast<CameraHardwareInterface *>(user);
+        __this->mNotifyCb(msg_type, ext1, ext2, __this->mCbUser);
+    }
+
+    static void __data_cb(int32_t msg_type,
+                          const camera_memory_t *data,
+                          void *user)
+    {
+        LOGV("%s", __FUNCTION__);
+        CameraHardwareInterface *__this =
+                static_cast<CameraHardwareInterface *>(user);
+        sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory *>(data->handle));
+        __this->mDataCb(msg_type, mem, __this->mCbUser);
+    }
+
+    static void __data_cb_timestamp(nsecs_t timestamp, int32_t msg_type,
+                             const camera_memory_t *data,
+                             void *user)
+    {
+        LOGV("%s", __FUNCTION__);
+        CameraHardwareInterface *__this =
+                static_cast<CameraHardwareInterface *>(user);
+        // Start refcounting the heap object from here on.  When the clients
+        // drop all references, it will be destroyed (as well as the enclosed
+        // MemoryHeapBase.
+        sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory *>(data->handle));
+        __this->mDataCbTimestamp(timestamp, msg_type, mem, __this->mCbUser);
+    }
+
+    // This is a utility class that combines a MemoryHeapBase and a MemoryBase
+    // in one.  Since we tend to use them in a one-to-one relationship, this is
+    // handy.
+
+    class CameraHeapMemory : public MemoryBase {
+    public:
+        CameraHeapMemory(size_t size) :
+            MemoryBase(new MemoryHeapBase(size), 0, size)
+        {
+            handle.data = getHeap()->base();
+            handle.size = size;
+            handle.handle = this;
+        }
+
+        camera_memory_t handle;
+    };
+
+    static camera_memory_t* __get_memory(size_t size,
+                                    void *user __attribute__((unused)))
+    {
+        // We allocate the object here, but we do not assign it to a strong
+        // pointer yet.  The HAL will pass it back to us via the data callback
+        // or the data-timestamp callback, and from there on we will wrap it
+        // within a strong pointer.
+
+        CameraHeapMemory *mem = new CameraHeapMemory(size);
+        return &mem->handle;
+    }
+
+    static ANativeWindow *__to_anw(void *user)
+    {
+        CameraHardwareInterface *__this =
+                reinterpret_cast<CameraHardwareInterface *>(user);
+        return __this->mPreviewWindow.get();
+    }
+#define anw(n) __to_anw(((struct camera_preview_window *)n)->user)
+
+    static int __dequeue_buffer(struct preview_stream_ops* w,
+                      buffer_handle_t** buffer)
+    {
+        int rc;
+        ANativeWindow *a = anw(w);
+        ANativeWindowBuffer* anb;
+        rc = a->dequeueBuffer(a, &anb);
+        if (!rc) {
+            rc = a->lockBuffer(a, anb);
+            if (!rc)
+                *buffer = &anb->handle;
+            else
+                a->cancelBuffer(a, anb);
+        }
+        return rc;
+    }
+
+#ifndef container_of
+#define container_of(ptr, type, member) ({                      \
+        const typeof(((type *) 0)->member) *__mptr = (ptr);     \
+        (type *) ((char *) __mptr - (char *)(&((type *)0)->member)); })
+#endif
+
+    static int __enqueue_buffer(struct preview_stream_ops* w,
+                      buffer_handle_t* buffer)
+    {
+        ANativeWindow *a = anw(w);
+        return a->queueBuffer(a,
+                  container_of(buffer, ANativeWindowBuffer, handle));
+    }
+
+    static int __cancel_buffer(struct preview_stream_ops* w,
+                      buffer_handle_t* buffer)
+    {
+        ANativeWindow *a = anw(w);
+        return a->cancelBuffer(a,
+                  container_of(buffer, ANativeWindowBuffer, handle));
+    }
+
+    static int __set_buffer_count(struct preview_stream_ops* w, int count)
+    {
+        ANativeWindow *a = anw(w);
+	return native_window_set_buffer_count(a, count);
+    }
+
+    static int __set_buffers_geometry(struct preview_stream_ops* w,
+                      int width, int height, int format)
+    {
+        ANativeWindow *a = anw(w);
+        return native_window_set_buffers_geometry(a,
+                          width, height, format);
+    }
+
+    static int __set_crop(struct preview_stream_ops *w,
+                      int left, int top, int right, int bottom)
+    {
+        ANativeWindow *a = anw(w);
+        android_native_rect_t crop;
+        crop.left = left;
+        crop.top = top;
+        crop.right = right;
+        crop.bottom = bottom;
+        return native_window_set_crop(a, &crop);
+    }
+
+    static int __set_usage(struct preview_stream_ops* w, int usage)
+    {
+        ANativeWindow *a = anw(w);
+        return native_window_set_usage(a, usage);
+    }
+
+    static int __set_swap_interval(struct preview_stream_ops *w, int interval)
+    {
+        ANativeWindow *a = anw(w);
+        return a->setSwapInterval(a, interval);
+    }
+
+    static int __get_min_undequeued_buffer_count(
+                      const struct preview_stream_ops *w,
+                      int *count)
+    {
+        ANativeWindow *a = anw(w);
+        return a->query(a, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, count);
+    }
+
+    void initHalPreviewWindow()
+    {
+        mHalPreviewWindow.nw.cancel_buffer = __cancel_buffer;
+        mHalPreviewWindow.nw.dequeue_buffer = __dequeue_buffer;
+        mHalPreviewWindow.nw.enqueue_buffer = __enqueue_buffer;
+        mHalPreviewWindow.nw.set_buffer_count = __set_buffer_count;
+        mHalPreviewWindow.nw.set_buffers_geometry = __set_buffers_geometry;
+        mHalPreviewWindow.nw.set_crop = __set_crop;
+        mHalPreviewWindow.nw.set_usage = __set_usage;
+        mHalPreviewWindow.nw.set_swap_interval = __set_swap_interval;
+
+        mHalPreviewWindow.nw.get_min_undequeued_buffer_count =
+                __get_min_undequeued_buffer_count;
+    }
+
+    sp<ANativeWindow>        mPreviewWindow;
+
+    struct camera_preview_window {
+        struct preview_stream_ops nw;
+        void *user;
+    };
+
+    struct camera_preview_window mHalPreviewWindow;
+
+    notify_callback         mNotifyCb;
+    data_callback           mDataCb;
+    data_callback_timestamp mDataCbTimestamp;
+    void *mCbUser;
+};
+
+};  // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index f4859ec..1e8c30b 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -16,6 +16,7 @@
 */
 
 #define LOG_TAG "CameraService"
+//#define LOG_NDEBUG 0
 
 #include <stdio.h>
 #include <sys/types.h>
@@ -37,6 +38,7 @@
 #include <utils/String16.h>
 
 #include "CameraService.h"
+#include "CameraHardwareInterface.h"
 
 namespace android {
 
@@ -69,24 +71,34 @@
 static CameraService *gCameraService;
 
 CameraService::CameraService()
-:mSoundRef(0)
+:mSoundRef(0), mModule(0)
 {
     LOGI("CameraService started (pid=%d)", getpid());
-
-    mNumberOfCameras = HAL_getNumberOfCameras();
-    if (mNumberOfCameras > MAX_CAMERAS) {
-        LOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
-             mNumberOfCameras, MAX_CAMERAS);
-        mNumberOfCameras = MAX_CAMERAS;
-    }
-
-    for (int i = 0; i < mNumberOfCameras; i++) {
-        setCameraFree(i);
-    }
-
     gCameraService = this;
 }
 
+void CameraService::onFirstRef()
+{
+    BnCameraService::onFirstRef();
+
+    if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,
+                (const hw_module_t **)&mModule) < 0) {
+        LOGE("Could not load camera HAL module");
+        mNumberOfCameras = 0;
+    }
+    else {
+        mNumberOfCameras = mModule->get_number_of_cameras();
+        if (mNumberOfCameras > MAX_CAMERAS) {
+            LOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
+                    mNumberOfCameras, MAX_CAMERAS);
+            mNumberOfCameras = MAX_CAMERAS;
+        }
+        for (int i = 0; i < mNumberOfCameras; i++) {
+            setCameraFree(i);
+        }
+    }
+}
+
 CameraService::~CameraService() {
     for (int i = 0; i < mNumberOfCameras; i++) {
         if (mBusy[i]) {
@@ -103,12 +115,19 @@
 
 status_t CameraService::getCameraInfo(int cameraId,
                                       struct CameraInfo* cameraInfo) {
+    if (!mModule) {
+        return NO_INIT;
+    }
+
     if (cameraId < 0 || cameraId >= mNumberOfCameras) {
         return BAD_VALUE;
     }
 
-    HAL_getCameraInfo(cameraId, cameraInfo);
-    return OK;
+    struct camera_info info;
+    status_t rc = mModule->get_camera_info(cameraId, &info);
+    cameraInfo->facing = info.facing;
+    cameraInfo->orientation = info.orientation;
+    return rc;
 }
 
 sp<ICamera> CameraService::connect(
@@ -116,6 +135,11 @@
     int callingPid = getCallingPid();
     LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId);
 
+    if (!mModule) {
+        LOGE("Camera HAL module not loaded");
+        return NULL;
+    }
+
     sp<Client> client;
     if (cameraId < 0 || cameraId >= mNumberOfCameras) {
         LOGE("CameraService::connect X (pid %d) rejected (invalid cameraId %d).",
@@ -146,15 +170,19 @@
         return NULL;
     }
 
-    sp<CameraHardwareInterface> hardware = HAL_openCameraHardware(cameraId);
-    if (hardware == NULL) {
-        LOGE("Fail to open camera hardware (id=%d)", cameraId);
+    struct camera_info info;
+    if (mModule->get_camera_info(cameraId, &info) != OK) {
+        LOGE("Invalid camera id %d", cameraId);
         return NULL;
     }
-    CameraInfo info;
-    HAL_getCameraInfo(cameraId, &info);
-    client = new Client(this, cameraClient, hardware, cameraId, info.facing,
-                        callingPid);
+
+    char camera_device_name[10];
+    snprintf(camera_device_name, sizeof(camera_device_name), "%d", cameraId);
+
+    client = new Client(this, cameraClient,
+                new CameraHardwareInterface(&mModule->common,
+                                            camera_device_name),
+                cameraId, info.facing, callingPid);
     mClient[cameraId] = client;
     LOG1("CameraService::connect X");
     return client;
@@ -320,7 +348,7 @@
                   CAMERA_MSG_FOCUS);
 
     // Callback is disabled by default
-    mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
+    mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
     mOrientation = getOrientation(0, mCameraFacing == CAMERA_FACING_FRONT);
     mPlayShutterSound = true;
     cameraService->setCameraBusy(cameraId);
@@ -410,7 +438,7 @@
         return NO_ERROR;
     }
 
-    mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
+    mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
     mClientPid = callingPid;
     mCameraClient = client;
 
@@ -543,7 +571,7 @@
     if (checkPidAndHardware() != NO_ERROR) return;
 
     mPreviewCallbackFlag = callback_flag;
-    if (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK) {
+    if (mPreviewCallbackFlag & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) {
         enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
     } else {
         disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
@@ -1009,7 +1037,7 @@
     int flags = mPreviewCallbackFlag;
 
     // is callback enabled?
-    if (!(flags & FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
+    if (!(flags & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
         // If the enable bit is off, the copy-out and one-shot bits are ignored
         LOG2("frame callback is disabled");
         mLock.unlock();
@@ -1020,17 +1048,17 @@
     sp<ICameraClient> c = mCameraClient;
 
     // clear callback flags if no client or one-shot mode
-    if (c == 0 || (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)) {
+    if (c == 0 || (mPreviewCallbackFlag & CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)) {
         LOG2("Disable preview callback");
-        mPreviewCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
-                                  FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
-                                  FRAME_CALLBACK_FLAG_ENABLE_MASK);
+        mPreviewCallbackFlag &= ~(CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
+                                  CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
+                                  CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
         disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
     }
 
     if (c != 0) {
         // Is the received frame copied out or not?
-        if (flags & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
+        if (flags & CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
             LOG2("frame is copied");
             copyFrameAndPostCopiedFrame(c, heap, offset, size);
         } else {
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 9a9ab0e..5e2d571 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -19,9 +19,8 @@
 #define ANDROID_SERVERS_CAMERA_CAMERASERVICE_H
 
 #include <binder/BinderService.h>
-
 #include <camera/ICameraService.h>
-#include <camera/CameraHardwareInterface.h>
+#include <hardware/camera.h>
 
 /* This needs to be increased if we can have more cameras */
 #define MAX_CAMERAS 2
@@ -30,6 +29,7 @@
 
 class MemoryHeapBase;
 class MediaPlayer;
+class CameraHardwareInterface;
 
 class CameraService :
     public BinderService<CameraService>,
@@ -53,6 +53,7 @@
     virtual status_t    dump(int fd, const Vector<String16>& args);
     virtual status_t    onTransact(uint32_t code, const Parcel& data,
                                    Parcel* reply, uint32_t flags);
+    virtual void onFirstRef();
 
     enum sound_kind {
         SOUND_SHUTTER = 0,
@@ -199,6 +200,8 @@
         // is found to be disabled. It returns true if mLock is grabbed.
         bool                    lockIfMessageWanted(int32_t msgType);
     };
+
+    camera_module_t *mModule;
 };
 
 } // namespace android
diff --git a/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp b/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
index 8a228fd..f86ca47 100644
--- a/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
+++ b/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
@@ -830,10 +830,10 @@
             ASSERT(c->previewEnabled() == true);
             sleep(2);
             c->stopPreview();
-            if ((v & FRAME_CALLBACK_FLAG_ENABLE_MASK) == 0) {
+            if ((v & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) == 0) {
                 cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, 0);
             } else {
-                if ((v & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) == 0) {
+                if ((v & CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) == 0) {
                     cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::GE, 10);
                 } else {
                     cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, 1);
@@ -849,7 +849,7 @@
         ASSERT(c->recordingEnabled() == false);
         sp<MSurface> surface = new MSurface();
         ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
-        c->setPreviewCallbackFlag(FRAME_CALLBACK_FLAG_ENABLE_MASK);
+        c->setPreviewCallbackFlag(CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
         cc->setReleaser(c.get());
         c->startRecording();
         ASSERT(c->recordingEnabled() == true);
@@ -870,7 +870,7 @@
 
         CameraParameters param(c->getParameters());
         param.setPreviewSize(w, h);
-        c->setPreviewCallbackFlag(FRAME_CALLBACK_FLAG_ENABLE_MASK);
+        c->setPreviewCallbackFlag(CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
         c->setParameters(param.flatten());
 
         c->startPreview();
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
index f04fb02..208353d 100644
--- a/services/input/InputWindow.h
+++ b/services/input/InputWindow.h
@@ -119,6 +119,7 @@
         TYPE_DRAG               = FIRST_SYSTEM_WINDOW+16,
         TYPE_STATUS_BAR_SUB_PANEL  = FIRST_SYSTEM_WINDOW+17,
         TYPE_POINTER            = FIRST_SYSTEM_WINDOW+18,
+        TYPE_NAVIGATION_BAR     = FIRST_SYSTEM_WINDOW+19,
         LAST_SYSTEM_WINDOW      = 2999,
     };
 
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 6c3b3d3..7272e76 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -34,6 +34,7 @@
 import android.net.NetworkUtils;
 import android.net.Proxy;
 import android.net.ProxyProperties;
+import android.net.RouteInfo;
 import android.net.vpn.VpnManager;
 import android.net.wifi.WifiStateTracker;
 import android.os.Binder;
@@ -708,9 +709,13 @@
                         mNetRequestersPids[usedNetworkType].add(currentPid);
                     }
                 }
-                mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK,
-                        f), getRestoreDefaultNetworkDelay());
 
+                int restoreTimer = getRestoreDefaultNetworkDelay(usedNetworkType);
+
+                if (restoreTimer >= 0) {
+                    mHandler.sendMessageDelayed(
+                            mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK, f), restoreTimer);
+                }
 
                 if ((ni.isConnectedOrConnecting() == true) &&
                         !network.isTeardownRequested()) {
@@ -1417,14 +1422,19 @@
         if (p == null) return;
         String interfaceName = p.getInterfaceName();
         if (TextUtils.isEmpty(interfaceName)) return;
-        for (InetAddress gateway : p.getGateways()) {
+        for (RouteInfo route : p.getRoutes()) {
 
-            if (NetworkUtils.addHostRoute(interfaceName, gateway, null) &&
-                    NetworkUtils.addDefaultRoute(interfaceName, gateway)) {
-                if (DBG) {
-                    NetworkInfo networkInfo = nt.getNetworkInfo();
-                    log("addDefaultRoute for " + networkInfo.getTypeName() +
-                            " (" + interfaceName + "), GatewayAddr=" + gateway.getHostAddress());
+            //TODO - handle non-default routes
+            if (route.isDefaultRoute()) {
+                InetAddress gateway = route.getGateway();
+                if (NetworkUtils.addHostRoute(interfaceName, gateway, null) &&
+                        NetworkUtils.addDefaultRoute(interfaceName, gateway)) {
+                    if (DBG) {
+                        NetworkInfo networkInfo = nt.getNetworkInfo();
+                        log("addDefaultRoute for " + networkInfo.getTypeName() +
+                                " (" + interfaceName + "), GatewayAddr=" +
+                                gateway.getHostAddress());
+                    }
                 }
             }
         }
@@ -1656,7 +1666,7 @@
         }
     }
 
-    private int getRestoreDefaultNetworkDelay() {
+    private int getRestoreDefaultNetworkDelay(int networkType) {
         String restoreDefaultNetworkDelayStr = SystemProperties.get(
                 NETWORK_RESTORE_DELAY_PROP_NAME);
         if(restoreDefaultNetworkDelayStr != null &&
@@ -1666,7 +1676,14 @@
             } catch (NumberFormatException e) {
             }
         }
-        return RESTORE_DEFAULT_NETWORK_DELAY;
+        // if the system property isn't set, use the value for the apn type
+        int ret = RESTORE_DEFAULT_NETWORK_DELAY;
+
+        if ((networkType <= ConnectivityManager.MAX_NETWORK_TYPE) &&
+                (mNetConfigs[networkType] != null)) {
+            ret = mNetConfigs[networkType].restoreTime;
+        }
+        return ret;
     }
 
     @Override
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 44f5df2..d931350 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -23,6 +23,7 @@
 import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.content.pm.PackageManager;
+import android.net.NetworkStats;
 import android.net.Uri;
 import android.net.InterfaceConfiguration;
 import android.net.INetworkManagementEventObserver;
@@ -32,6 +33,8 @@
 import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.os.INetworkManagementService;
 import android.os.Handler;
+import android.os.RemoteException;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.text.TextUtils;
 import android.util.Log;
@@ -44,13 +47,21 @@
 import android.database.ContentObserver;
 
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.RandomAccessFile;
+import java.io.Reader;
 import java.lang.IllegalStateException;
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.concurrent.CountDownLatch;
 
+import libcore.io.IoUtils;
+
 /**
  * @hide
  */
@@ -716,12 +727,47 @@
         return -1;
     }
 
-    public long getInterfaceRxCounter(String iface) {
-        return getInterfaceCounter(iface, true);
+    /** {@inheritDoc} */
+    public NetworkStats getNetworkStatsSummary() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+        final String[] ifaces = listInterfaces();
+        final NetworkStats.Builder stats = new NetworkStats.Builder(
+                SystemClock.elapsedRealtime(), ifaces.length);
+
+        for (String iface : ifaces) {
+            final long rx = getInterfaceCounter(iface, true);
+            final long tx = getInterfaceCounter(iface, false);
+            stats.addEntry(iface, NetworkStats.UID_ALL, rx, tx);
+        }
+
+        return stats.build();
     }
 
-    public long getInterfaceTxCounter(String iface) {
-        return getInterfaceCounter(iface, false);
+    /** {@inheritDoc} */
+    public NetworkStats getNetworkStatsDetail() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+        final File procPath = new File("/proc/uid_stat");
+        final String[] knownUids = procPath.list();
+        final NetworkStats.Builder stats = new NetworkStats.Builder(
+                SystemClock.elapsedRealtime(), knownUids.length);
+
+        // TODO: kernel module will provide interface-level stats in future
+        // TODO: migrate these stats to come across netd in bulk, instead of all
+        // these individual file reads.
+        for (String uid : knownUids) {
+            final File uidPath = new File(procPath, uid);
+            final int rx = readSingleIntFromFile(new File(uidPath, "tcp_rcv"));
+            final int tx = readSingleIntFromFile(new File(uidPath, "tcp_snd"));
+
+            final int uidInt = Integer.parseInt(uid);
+            stats.addEntry(NetworkStats.IFACE_ALL, uidInt, rx, tx);
+        }
+
+        return stats.build();
     }
 
     public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
@@ -782,4 +828,24 @@
     public int getInterfaceTxThrottle(String iface) {
         return getInterfaceThrottle(iface, false);
     }
+
+    /**
+     * Utility method to read a single plain-text {@link Integer} from the given
+     * {@link File}, usually from a {@code /proc/} filesystem.
+     */
+    private static int readSingleIntFromFile(File file) {
+        RandomAccessFile f = null;
+        try {
+            f = new RandomAccessFile(file, "r");
+            byte[] buffer = new byte[(int) f.length()];
+            f.readFully(buffer);
+            return Integer.parseInt(new String(buffer).trim());
+        } catch (NumberFormatException e) {
+            return -1;
+        } catch (IOException e) {
+            return -1;
+        } finally {
+            IoUtils.closeQuietly(f);
+        }
+    }
 }
diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java
index 02332b7..510ff62 100644
--- a/services/java/com/android/server/ThrottleService.java
+++ b/services/java/com/android/server/ThrottleService.java
@@ -33,6 +33,7 @@
 import android.database.ContentObserver;
 import android.net.INetworkManagementEventObserver;
 import android.net.IThrottleManager;
+import android.net.NetworkStats;
 import android.net.ThrottleManager;
 import android.os.Binder;
 import android.os.Environment;
@@ -531,8 +532,17 @@
             long incRead = 0;
             long incWrite = 0;
             try {
-                incRead = mNMService.getInterfaceRxCounter(mIface) - mLastRead;
-                incWrite = mNMService.getInterfaceTxCounter(mIface) - mLastWrite;
+                final NetworkStats stats = mNMService.getNetworkStatsSummary();
+                final int index = stats.findIndex(mIface, NetworkStats.UID_ALL);
+
+                if (index != -1) {
+                    incRead = stats.rx[index] - mLastRead;
+                    incWrite = stats.tx[index] - mLastWrite;
+                } else {
+                    // missing iface, assume stats are 0
+                    Slog.w(TAG, "unable to find stats for iface " + mIface);
+                }
+
                 // handle iface resets - on some device the 3g iface comes and goes and gets
                 // totals reset to 0.  Deal with it
                 if ((incRead < 0) || (incWrite < 0)) {
diff --git a/services/java/com/android/server/WifiWatchdogService.java b/services/java/com/android/server/WifiWatchdogService.java
index bf1b6e6..6ef6963 100644
--- a/services/java/com/android/server/WifiWatchdogService.java
+++ b/services/java/com/android/server/WifiWatchdogService.java
@@ -28,6 +28,7 @@
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
+import android.net.Uri;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -508,6 +509,7 @@
             // This access point does not require a watchdog, so queue idle on the main thread
             mHandler.idle();
         }
+        mHandler.checkWalledGarden(ssid);
     }
     
     /**
@@ -1002,6 +1004,8 @@
          * The object will be an {@link AccessPoint}.
          */
         static final int ACTION_BACKGROUND_CHECK_AP = 3;
+        /** Check whether the connection is a walled garden */
+        static final int ACTION_CHECK_WALLED_GARDEN = 4;
 
         /**
          * Go to sleep for the current network. We are conservative with making
@@ -1022,7 +1026,16 @@
         static final int MESSAGE_DISCONNECTED = 104;
         /** Performs a hard-reset on the watchdog state. */
         static final int MESSAGE_RESET = 105;
-        
+
+        /* Walled garden detection */
+        private String mLastSsid;
+        private long mLastTime;
+        private final long MIN_WALLED_GARDEN_TEST_INTERVAL = 15 * 60 * 1000; //15 minutes
+
+        void checkWalledGarden(String ssid) {
+            sendMessage(obtainMessage(ACTION_CHECK_WALLED_GARDEN, ssid));
+        }
+
         void checkAp(AccessPoint ap) {
             removeAllActions();
             sendMessage(obtainMessage(ACTION_CHECK_AP, ap));
@@ -1084,6 +1097,9 @@
                 case ACTION_BACKGROUND_CHECK_AP:
                     handleBackgroundCheckAp((AccessPoint) msg.obj);
                     break;
+                case ACTION_CHECK_WALLED_GARDEN:
+                    handleWalledGardenCheck((String) msg.obj);
+                    break;
                 case MESSAGE_SLEEP:
                     handleSleep((String) msg.obj);
                     break;
@@ -1101,6 +1117,43 @@
                     break;
             }
         }
+
+        private boolean isWalledGardenConnection() {
+            //One way to detect a walled garden is to see if multiple DNS queries
+            //resolve to the same IP address
+            try {
+                String host1 = "www.google.com";
+                String host2 = "www.android.com";
+                String address1 = InetAddress.getByName(host1).getHostAddress();
+                String address2 = InetAddress.getByName(host2).getHostAddress();
+                if (address1.equals(address2)) return true;
+            } catch (UnknownHostException e) {
+                return false;
+            }
+            return false;
+        }
+
+        private void handleWalledGardenCheck(String ssid) {
+            long currentTime = System.currentTimeMillis();
+            //Avoid a walled garden test on the same network if one was already done
+            //within MIN_WALLED_GARDEN_TEST_INTERVAL. This will handle scenarios where
+            //there are frequent network disconnections
+            if (ssid.equals(mLastSsid) &&
+                    (currentTime - mLastTime) < MIN_WALLED_GARDEN_TEST_INTERVAL) {
+                return;
+            }
+
+            mLastTime = currentTime;
+            mLastSsid = ssid;
+
+            if (isWalledGardenConnection()) {
+                Uri uri = Uri.parse("http://www.google.com");
+                Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+                intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
+                        Intent.FLAG_ACTIVITY_NEW_TASK);
+                mContext.startActivity(intent);
+            }
+        }
     }
 
     /**
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 31b7f86..da34644 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -7091,18 +7091,25 @@
      * to append various headers to the dropbox log text.
      */
     private void appendDropBoxProcessHeaders(ProcessRecord process, StringBuilder sb) {
+        // Watchdog thread ends up invoking this function (with
+        // a null ProcessRecord) to add the stack file to dropbox.
+        // Do not acquire a lock on this (am) in such cases, as it
+        // could cause a potential deadlock, if and when watchdog
+        // is invoked due to unavailability of lock on am and it
+        // would prevent watchdog from killing system_server.
+        if (process == null) {
+            sb.append("Process: system_server\n");
+            return;
+        }
         // Note: ProcessRecord 'process' is guarded by the service
         // instance.  (notably process.pkgList, which could otherwise change
         // concurrently during execution of this method)
         synchronized (this) {
-            if (process == null || process.pid == MY_PID) {
+            if (process.pid == MY_PID) {
                 sb.append("Process: system_server\n");
             } else {
                 sb.append("Process: ").append(process.processName).append("\n");
             }
-            if (process == null) {
-                return;
-            }
             int flags = process.info.flags;
             IPackageManager pm = AppGlobals.getPackageManager();
             sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n");
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index da00c0c..004e963 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -202,7 +202,9 @@
         long now = SystemClock.uptimeMillis();
         long nowReal = SystemClock.elapsedRealtime();
         pw.print(prefix); pw.print("baseDir="); pw.println(baseDir);
-        if (!resDir.equals(baseDir)) pw.print(prefix); pw.print("resDir="); pw.println(resDir);
+        if (!resDir.equals(baseDir)) {
+            pw.print(prefix); pw.print("resDir="); pw.println(resDir);
+        }
         pw.print(prefix); pw.print("dataDir="); pw.println(dataDir);
         pw.print(prefix); pw.print("app="); pw.println(app);
         if (isForeground || foregroundId != 0) {
diff --git a/services/java/com/android/server/wm/ViewServer.java b/services/java/com/android/server/wm/ViewServer.java
index cebd5e7..9fb35b9 100644
--- a/services/java/com/android/server/wm/ViewServer.java
+++ b/services/java/com/android/server/wm/ViewServer.java
@@ -49,7 +49,7 @@
     // Debug facility
     private static final String LOG_TAG = "ViewServer";
 
-    private static final String VALUE_PROTOCOL_VERSION = "3";
+    private static final String VALUE_PROTOCOL_VERSION = "4";
     private static final String VALUE_SERVER_VERSION = "4";
 
     // Protocol commands
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7506f29..e8f0328 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -395,7 +395,7 @@
     if (LIKELY(mTransactionCount == 0)) {
         // if we're in a global transaction, don't do anything.
         const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
-        uint32_t transactionFlags = getTransactionFlags(mask);
+        uint32_t transactionFlags = peekTransactionFlags(mask);
         if (LIKELY(transactionFlags)) {
             handleTransaction(transactionFlags);
         }
@@ -490,7 +490,17 @@
         Mutex::Autolock _l(mStateLock);
         const nsecs_t now = systemTime();
         mDebugInTransaction = now;
+
+        // Here we're guaranteed that some transaction flags are set
+        // so we can call handleTransactionLocked() unconditionally.
+        // We call getTransactionFlags(), which will also clear the flags,
+        // with mStateLock held to guarantee that mCurrentState won't change
+        // until the transaction is commited.
+
+        const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
+        transactionFlags = getTransactionFlags(mask);
         handleTransactionLocked(transactionFlags, ditchedLayers);
+
         mLastTransactionTime = systemTime() - now;
         mDebugInTransaction = 0;
         invalidateHwcGeometry();
@@ -1094,15 +1104,15 @@
 ssize_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
         const sp<LayerBaseClient>& lbc)
 {
-    Mutex::Autolock _l(mStateLock);
-
     // attach this layer to the client
-    ssize_t name = client->attachLayer(lbc);
+    size_t name = client->attachLayer(lbc);
+
+    Mutex::Autolock _l(mStateLock);
 
     // add this layer to the current state list
     addLayer_l(lbc);
 
-    return name;
+    return ssize_t(name);
 }
 
 status_t SurfaceFlinger::removeLayer(const sp<LayerBase>& layer)
@@ -1153,6 +1163,11 @@
     return NO_ERROR;
 }
 
+uint32_t SurfaceFlinger::peekTransactionFlags(uint32_t flags)
+{
+    return android_atomic_release_load(&mTransactionFlags);
+}
+
 uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags)
 {
     return android_atomic_and(~flags, &mTransactionFlags) & flags;
@@ -2381,15 +2396,17 @@
     return NO_ERROR;
 }
 
-ssize_t Client::attachLayer(const sp<LayerBaseClient>& layer)
+size_t Client::attachLayer(const sp<LayerBaseClient>& layer)
 {
-    int32_t name = android_atomic_inc(&mNameGenerator);
+    Mutex::Autolock _l(mLock);
+    size_t name = mNameGenerator++;
     mLayers.add(name, layer);
     return name;
 }
 
 void Client::detachLayer(const LayerBaseClient* layer)
 {
+    Mutex::Autolock _l(mLock);
     // we do a linear search here, because this doesn't happen often
     const size_t count = mLayers.size();
     for (size_t i=0 ; i<count ; i++) {
@@ -2399,9 +2416,11 @@
         }
     }
 }
-sp<LayerBaseClient> Client::getLayerUser(int32_t i) const {
+sp<LayerBaseClient> Client::getLayerUser(int32_t i) const
+{
+    Mutex::Autolock _l(mLock);
     sp<LayerBaseClient> lbc;
-    const wp<LayerBaseClient>& layer(mLayers.valueFor(i));
+    wp<LayerBaseClient> layer(mLayers.valueFor(i));
     if (layer != 0) {
         lbc = layer.promote();
         LOGE_IF(lbc==0, "getLayerUser(name=%d) is dead", int(i));
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 1b36d1c..1e16943 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -65,7 +65,7 @@
     status_t initCheck() const;
 
     // protected by SurfaceFlinger::mStateLock
-    ssize_t attachLayer(const sp<LayerBaseClient>& layer);
+    size_t attachLayer(const sp<LayerBaseClient>& layer);
     void detachLayer(const LayerBaseClient* layer);
     sp<LayerBaseClient> getLayerUser(int32_t i) const;
 
@@ -81,9 +81,15 @@
     virtual status_t destroySurface(SurfaceID surfaceId);
     virtual status_t setState(int32_t count, const layer_state_t* states);
 
-    DefaultKeyedVector< size_t, wp<LayerBaseClient> > mLayers;
+    // constant
     sp<SurfaceFlinger> mFlinger;
-    int32_t mNameGenerator;
+
+    // protected by mLock
+    DefaultKeyedVector< size_t, wp<LayerBaseClient> > mLayers;
+    size_t mNameGenerator;
+
+    // thread-safe
+    mutable Mutex mLock;
 };
 
 class UserClient : public BnSurfaceComposerClient
@@ -319,6 +325,7 @@
             status_t    purgatorizeLayer_l(const sp<LayerBase>& layer);
 
             uint32_t    getTransactionFlags(uint32_t flags);
+            uint32_t    peekTransactionFlags(uint32_t flags);
             uint32_t    setTransactionFlags(uint32_t flags);
             void        commitTransaction();
 
diff --git a/services/surfaceflinger/TextureManager.cpp b/services/surfaceflinger/TextureManager.cpp
index c9a15f5..bb63c37 100644
--- a/services/surfaceflinger/TextureManager.cpp
+++ b/services/surfaceflinger/TextureManager.cpp
@@ -144,7 +144,7 @@
     }
 
     // construct an EGL_NATIVE_BUFFER_ANDROID
-    android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
+    ANativeWindowBuffer* clientBuf = buffer->getNativeBuffer();
 
     // create the new EGLImageKHR
     const EGLint attrs[] = {
@@ -186,7 +186,7 @@
     if (texture->name == -1UL) {
         status_t err = initTexture(texture);
         LOGE_IF(err, "loadTexture failed in initTexture (%s)", strerror(err));
-        return err;
+        if (err != NO_ERROR) return err;
     }
 
     if (texture->target != Texture::TEXTURE_2D)
diff --git a/services/surfaceflinger/tests/surface/surface.cpp b/services/surfaceflinger/tests/surface/surface.cpp
index 67ecf7e..5265f91 100644
--- a/services/surfaceflinger/tests/surface/surface.cpp
+++ b/services/surfaceflinger/tests/surface/surface.cpp
@@ -53,7 +53,7 @@
     printf("window=%p\n", window);
 
     int err = native_window_set_buffer_count(window, 8);
-    android_native_buffer_t* buffer;
+    ANativeWindowBuffer* buffer;
 
     for (int i=0 ; i<8 ; i++) {
         window->dequeueBuffer(window, &buffer);
diff --git a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
index 6f55f46..f20d5e5 100644
--- a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
@@ -34,11 +34,17 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.INetworkManagementEventObserver;
+import android.net.NetworkStats;
 import android.net.ThrottleManager;
+import android.os.IBinder;
 import android.os.INetworkManagementService;
+import android.os.ServiceManager;
+import android.os.SystemClock;
 import android.provider.Settings;
 import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.Suppress;
 import android.text.format.DateUtils;
+import android.util.Log;
 import android.util.TrustedTime;
 
 import java.util.Iterator;
@@ -222,6 +228,16 @@
         verify(mMockTime, mMockNMService);
     }
 
+    @Suppress
+    public void testReturnStats() throws Exception {
+        final IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+        final INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b);
+
+        // test is currently no-op, just exercises stats apis
+        Log.d(TAG, nmService.getNetworkStatsSummary().toString());
+        Log.d(TAG, nmService.getNetworkStatsDetail().toString());
+    }
+
     /**
      * Persist the given {@link ThrottleService} policy into {@link Settings}.
      */
@@ -272,12 +288,16 @@
     }
 
     /**
-     * Expect {@link NetworkManagementService#getInterfaceRxCounter} mock calls,
-     * responding with the given counter values.
+     * Expect {@link NetworkManagementService#getNetworkStatsSummary()} mock
+     * calls, responding with the given counter values.
      */
     public void expectGetInterfaceCounter(long rx, long tx) throws Exception {
-        expect(mMockNMService.getInterfaceRxCounter(isA(String.class))).andReturn(rx).atLeastOnce();
-        expect(mMockNMService.getInterfaceTxCounter(isA(String.class))).andReturn(tx).atLeastOnce();
+        // TODO: provide elapsedRealtime mock to match TimeAuthority
+        final NetworkStats.Builder stats = new NetworkStats.Builder(
+                SystemClock.elapsedRealtime(), 1);
+        stats.addEntry(TEST_IFACE, NetworkStats.UID_ALL, rx, tx);
+
+        expect(mMockNMService.getNetworkStatsSummary()).andReturn(stats.build()).atLeastOnce();
     }
 
     /**
diff --git a/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java b/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java
index 6390d8e..f5e53ef 100644
--- a/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java
+++ b/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java
@@ -24,6 +24,7 @@
  *
  * 022-229-1234 0223-23-1234 022-301-9876 015-482-7849 0154-91-3478
  * 01547-5-4534 090-1234-1234 080-0123-6789
+ * 050-0000-0000 060-0000-0000
  * 0800-000-9999 0570-000-000 0276-00-0000
  *
  * As you can see, there is no straight-forward rule here.
@@ -31,7 +32,7 @@
  */
 /* package */ class JapanesePhoneNumberFormatter {
     private static short FORMAT_MAP[] = {
-    -100, 10, 220, -15, 410, 530, -15, 670, 780, 1060,
+    -100, 10, 220, -15, 410, 530, 1200, 670, 780, 1060,
     -100, -25, 20, 40, 70, 100, 150, 190, 200, 210,
     -36, -100, -100, -35, -35, -35, 30, -100, -100, -100,
     -35, -35, -35, -35, -35, -35, -35, -45, -35, -35,
@@ -84,7 +85,7 @@
     -35, -25, -25, -25, -25, -25, -25, -25, -25, -25,
     -25, -25, -25, -35, -35, -35, -25, -25, -25, 520,
     -100, -100, -45, -100, -45, -100, -45, -100, -45, -100,
-    -25, -100, -25, 540, 580, 590, 600, 610, 630, 640,
+    -26, -100, -25, 540, 580, 590, 600, 610, 630, 640,
     -25, -35, -35, -35, -25, -25, -35, -35, -35, 550,
     -35, -35, -25, -25, -25, -25, 560, 570, -25, -35,
     -35, -35, -35, -35, -25, -25, -25, -25, -25, -25,
@@ -150,7 +151,8 @@
     -35, 1170, -25, -35, 1180, -35, 1190, -35, -25, -25,
     -100, -100, -45, -45, -100, -100, -100, -100, -100, -100,
     -25, -35, -35, -35, -35, -35, -35, -25, -25, -35,
-    -35, -35, -35, -35, -35, -35, -35, -35, -35, -45};
+    -35, -35, -35, -35, -35, -35, -35, -35, -35, -45,
+    -26, -15, -15, -15, -15, -15, -15, -15, -15, -15};
 
     public static void format(Editable text) {
         // Here, "root" means the position of "'":
diff --git a/telephony/java/com/android/internal/telephony/ApnContext.java b/telephony/java/com/android/internal/telephony/ApnContext.java
index 3f1ca9e..010d61d 100644
--- a/telephony/java/com/android/internal/telephony/ApnContext.java
+++ b/telephony/java/com/android/internal/telephony/ApnContext.java
@@ -51,6 +51,8 @@
 
     DataConnection mDataConnection;
 
+    DataConnectionAc mDataConnectionAc;
+
     String mReason;
 
     PendingIntent mReconnectIntent;
@@ -96,6 +98,17 @@
         mDataConnection = dataConnection;
     }
 
+
+    public synchronized DataConnectionAc getDataConnectionAc() {
+        log("getDataConnectionAc dcac=" + mDataConnectionAc);
+        return mDataConnectionAc;
+    }
+
+    public synchronized void setDataConnectionAc(DataConnectionAc dcac) {
+        log("setDataConnectionAc dcac=" + dcac);
+        mDataConnectionAc = dcac;
+    }
+
     public synchronized ApnSetting getApnSetting() {
         return mApnSetting;
     }
@@ -206,6 +219,11 @@
        return mDependencyMet.get();
     }
 
+    @Override
+    public String toString() {
+        return "state=" + getState() + " apnType=" + mApnType;
+    }
+
     protected void log(String s) {
         Log.d(LOG_TAG, "[ApnContext] " + s);
     }
diff --git a/telephony/java/com/android/internal/telephony/DataCallState.java b/telephony/java/com/android/internal/telephony/DataCallState.java
index a883e8e..1d67d45 100644
--- a/telephony/java/com/android/internal/telephony/DataCallState.java
+++ b/telephony/java/com/android/internal/telephony/DataCallState.java
@@ -20,6 +20,7 @@
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.NetworkUtils;
+import android.net.RouteInfo;
 import android.os.SystemProperties;
 import android.util.Log;
 
@@ -196,7 +197,7 @@
                     } catch (IllegalArgumentException e) {
                         throw new UnknownHostException("Non-numeric gateway addr=" + addr);
                     }
-                    linkProperties.addGateway(ia);
+                    linkProperties.addRoute(new RouteInfo(ia));
                 }
 
                 result = SetupResult.SUCCESS;
@@ -223,5 +224,3 @@
         return result;
     }
 }
-
-
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 791fbfd..c4359a9 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -17,22 +17,24 @@
 package com.android.internal.telephony;
 
 
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
 
-import android.net.LinkAddress;
 import android.net.LinkCapabilities;
 import android.net.LinkProperties;
-import android.net.NetworkUtils;
+import android.net.ProxyProperties;
 import android.os.AsyncResult;
+import android.os.Bundle;
 import android.os.Message;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.SystemProperties;
 import android.text.TextUtils;
 
-import java.net.InetAddress;
-import java.net.Inet4Address;
-import java.net.UnknownHostException;
 import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * {@hide}
@@ -60,6 +62,8 @@
 
     protected static Object mCountLock = new Object();
     protected static int mCount;
+    protected AsyncChannel mAc;
+
 
     /**
      * Used internally for saving connecting parameters.
@@ -76,13 +80,6 @@
     }
 
     /**
-     * An instance used for notification of blockingReset.
-     * TODO: Remove when blockingReset is removed.
-     */
-    class ResetSynchronouslyLock {
-    }
-
-    /**
      * Used internally for saving disconnecting parameters.
      */
     protected static class DisconnectParams {
@@ -90,15 +87,9 @@
             this.reason = reason;
             this.onCompletedMsg = onCompletedMsg;
         }
-        public DisconnectParams(ResetSynchronouslyLock lockObj) {
-            this.reason = null;
-            this.lockObj = lockObj;
-        }
-
         public int tag;
         public String reason;
         public Message onCompletedMsg;
-        public ResetSynchronouslyLock lockObj;
     }
 
     /**
@@ -188,13 +179,13 @@
     }
 
     // ***** Event codes for driving the state machine
-    protected static final int EVENT_RESET = 1;
-    protected static final int EVENT_CONNECT = 2;
-    protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = 3;
-    protected static final int EVENT_GET_LAST_FAIL_DONE = 4;
-    protected static final int EVENT_DEACTIVATE_DONE = 5;
-    protected static final int EVENT_DISCONNECT = 6;
-    protected static final int EVENT_RIL_CONNECTED = 7;
+    protected static final int BASE = Protocol.BASE_DATA_CONNECTION;
+    protected static final int EVENT_CONNECT = BASE + 0;
+    protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = BASE + 1;
+    protected static final int EVENT_GET_LAST_FAIL_DONE = BASE + 2;
+    protected static final int EVENT_DEACTIVATE_DONE = BASE + 3;
+    protected static final int EVENT_DISCONNECT = BASE + 4;
+    protected static final int EVENT_RIL_CONNECTED = BASE + 5;
 
     //***** Tag IDs for EventLog
     protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100;
@@ -313,13 +304,8 @@
             AsyncResult.forMessage(msg);
             msg.sendToTarget();
         }
-        if (dp.lockObj != null) {
-            synchronized(dp.lockObj) {
-                dp.lockObj.notify();
-            }
-        }
-
         clearSettings();
+        if (DBG) log("NotifyDisconnectCompleted DisconnectParams=" + dp);
     }
 
     protected int getRadioTechnology(int defaultRadioTechnology) {
@@ -408,6 +394,49 @@
         return mRetryMgr.isRetryForever();
     }
 
+    private AtomicInteger mRefCount = new AtomicInteger(0);
+
+    /**
+     * Set refCount.
+     *
+     * @param val is new refCount
+     */
+    public void setRefCount(int val) {
+        mRefCount.set(val);
+    }
+
+    /**
+     * Get refCount
+     *
+     * @return refCount
+     */
+    public int getRefCount() {
+        return mRefCount.get();
+    }
+
+    /**
+     * @return decrement and return refCount
+     *
+     * TODO: Consider using the refCount for defining the
+     * life time of a connection. When this goes zero the
+     * DataConnection could tear itself down.
+     */
+    public int decAndGetRefCount() {
+        int v = mRefCount.decrementAndGet();
+        if (v < 0) {
+            log("BUG: decAndGetRefCount caused refCount to be < 0");
+            mRefCount.set(0);
+        }
+        return v;
+     }
+
+    /**
+     * @return increment and return refCount
+     */
+    public int incAndGetRefCount() {
+        return mRefCount.incrementAndGet();
+    }
+
     /*
      * **************************************************************************
      * End members owned by DataConnectionTracker
@@ -461,6 +490,9 @@
                 log("BUG: onSetupConnectionCompleted is stale cp.tag=" + cp.tag + ", mtag=" + mTag);
             }
             result = DataCallState.SetupResult.ERR_Stale;
+        } else if (response.status != 0) {
+            result = DataCallState.SetupResult.ERR_RilError;
+            result.mFailCause = FailCause.fromInt(response.status);
         } else {
             log("onSetupConnectionCompleted received DataCallState: " + response);
 
@@ -498,12 +530,74 @@
             AsyncResult ar;
 
             switch (msg.what) {
-                case EVENT_RESET:
-                    if (DBG) log("DcDefaultState: msg.what=EVENT_RESET");
-                    clearSettings();
-                    if (msg.obj != null) {
-                        notifyDisconnectCompleted((DisconnectParams) msg.obj);
+                case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
+                    if (mAc != null) {
+                        log("Disconnecting to previous connection mAc=" + mAc);
+                        mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
+                                AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED);
+                    } else {
+                        mAc = new AsyncChannel();
+                        mAc.connected(null, getHandler(), msg.replyTo);
+                        log("DcDefaultState: FULL_CONNECTION reply connected");
+                        mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
+                                AsyncChannel.STATUS_SUCCESSFUL, mId, "hi");
                     }
+                    break;
+                }
+                case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
+                    log("CMD_CHANNEL_DISCONNECT");
+                    mAc.disconnect();
+                    break;
+                }
+                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
+                    log("CMD_CHANNEL_DISCONNECTED");
+                    mAc = null;
+                    break;
+                }
+                case DataConnectionAc.REQ_IS_INACTIVE: {
+                    boolean val = getCurrentState() == mInactiveState;
+                    log("REQ_IS_INACTIVE  isInactive=" + val);
+                    mAc.replyToMessage(msg, DataConnectionAc.RSP_IS_INACTIVE, val ? 1 : 0);
+                    break;
+                }
+                case DataConnectionAc.REQ_GET_CID: {
+                    log("REQ_GET_CID  cid=" + cid);
+                    mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_CID, cid);
+                    break;
+                }
+                case DataConnectionAc.REQ_GET_APNSETTING: {
+                    log("REQ_GET_APNSETTING  apnSetting=" + mApn);
+                    mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_APNSETTING, mApn);
+                    break;
+                }
+                case DataConnectionAc.REQ_GET_LINK_PROPERTIES: {
+                    LinkProperties lp = new LinkProperties(mLinkProperties);
+                    log("REQ_GET_LINK_PROPERTIES linkProperties" + lp);
+                    mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_LINK_PROPERTIES, lp);
+                    break;
+                }
+                case DataConnectionAc.REQ_SET_LINK_PROPERTIES_HTTP_PROXY: {
+                    ProxyProperties proxy = (ProxyProperties) msg.obj;
+                    log("REQ_SET_LINK_PROPERTIES_HTTP_PROXY proxy=" + proxy);
+                    mLinkProperties.setHttpProxy(proxy);
+                    mAc.replyToMessage(msg, DataConnectionAc.RSP_SET_LINK_PROPERTIES_HTTP_PROXY);
+                    break;
+                }
+                case DataConnectionAc.REQ_GET_LINK_CAPABILITIES: {
+                    LinkCapabilities lc = new LinkCapabilities(mCapabilities);
+                    log("REQ_GET_LINK_CAPABILITIES linkCapabilities" + lc);
+                    mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_LINK_CAPABILITIES, lc);
+                    break;
+                }
+                case DataConnectionAc.REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE: {
+                    Bundle data = msg.getData();
+                    mLinkProperties = (LinkProperties) data.get("linkProperties");
+                    break;
+                }
+                case DataConnectionAc.REQ_RESET:
+                    if (DBG) log("DcDefaultState: msg.what=REQ_RESET");
+                    clearSettings();
+                    mAc.replyToMessage(msg, DataConnectionAc.RSP_RESET);
                     transitionTo(mInactiveState);
                     break;
 
@@ -539,7 +633,7 @@
                     break;
             }
 
-            return true;
+            return HANDLED;
         }
     }
     private DcDefaultState mDefaultState = new DcDefaultState();
@@ -597,14 +691,12 @@
             boolean retVal;
 
             switch (msg.what) {
-                case EVENT_RESET:
+                case DataConnectionAc.REQ_RESET:
                     if (DBG) {
-                        log("DcInactiveState: msg.what=EVENT_RESET, ignore we're already reset");
+                        log("DcInactiveState: msg.what=RSP_RESET, ignore we're already reset");
                     }
-                    if (msg.obj != null) {
-                        notifyDisconnectCompleted((DisconnectParams) msg.obj);
-                    }
-                    retVal = true;
+                    mAc.replyToMessage(msg, DataConnectionAc.RSP_RESET);
+                    retVal = HANDLED;
                     break;
 
                 case EVENT_CONNECT:
@@ -613,12 +705,12 @@
                     cp.tag = mTag;
                     onConnect(cp);
                     transitionTo(mActivatingState);
-                    retVal = true;
+                    retVal = HANDLED;
                     break;
 
                 default:
                     if (DBG) log("DcInactiveState nothandled msg.what=" + msg.what);
-                    retVal = false;
+                    retVal = NOT_HANDLED;
                     break;
             }
             return retVal;
@@ -640,7 +732,7 @@
                 case EVENT_DISCONNECT:
                     if (DBG) log("DcActivatingState deferring msg.what=EVENT_DISCONNECT");
                     deferMessage(msg);
-                    retVal = true;
+                    retVal = HANDLED;
                     break;
 
                 case EVENT_SETUP_DATA_CONNECTION_DONE:
@@ -685,7 +777,7 @@
                         default:
                             throw new RuntimeException("Unknown SetupResult, should not happen");
                     }
-                    retVal = true;
+                    retVal = HANDLED;
                     break;
 
                 case EVENT_GET_LAST_FAIL_DONE:
@@ -710,12 +802,12 @@
                         }
                     }
 
-                    retVal = true;
+                    retVal = HANDLED;
                     break;
 
                 default:
                     if (DBG) log("DcActivatingState not handled msg.what=" + msg.what);
-                    retVal = false;
+                    retVal = NOT_HANDLED;
                     break;
             }
             return retVal;
@@ -768,12 +860,12 @@
                     dp.tag = mTag;
                     tearDownData(dp);
                     transitionTo(mDisconnectingState);
-                    retVal = true;
+                    retVal = HANDLED;
                     break;
 
                 default:
                     if (DBG) log("DcActiveState nothandled msg.what=" + msg.what);
-                    retVal = false;
+                    retVal = NOT_HANDLED;
                     break;
             }
             return retVal;
@@ -803,12 +895,12 @@
                         if (DBG) log("DcDisconnectState EVENT_DEACTIVATE_DONE stale dp.tag="
                                 + dp.tag + " mTag=" + mTag);
                     }
-                    retVal = true;
+                    retVal = HANDLED;
                     break;
 
                 default:
                     if (DBG) log("DcDisconnectingState not handled msg.what=" + msg.what);
-                    retVal = false;
+                    retVal = NOT_HANDLED;
                     break;
             }
             return retVal;
@@ -845,7 +937,7 @@
                                     " stale dp.tag=" + cp.tag + ", mTag=" + mTag);
                         }
                     }
-                    retVal = true;
+                    retVal = HANDLED;
                     break;
 
                 default:
@@ -853,7 +945,7 @@
                         log("DcDisconnectionErrorCreatingConnection not handled msg.what="
                                 + msg.what);
                     }
-                    retVal = false;
+                    retVal = NOT_HANDLED;
                     break;
             }
             return retVal;
@@ -865,147 +957,26 @@
     // ******* public interface
 
     /**
-     * Disconnect from the network.
-     *
-     * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
-     *        With AsyncResult.userObj set to the original msg.obj.
-     */
-    public void reset(Message onCompletedMsg) {
-        sendMessage(obtainMessage(EVENT_RESET, new DisconnectParams(null, onCompletedMsg)));
-    }
-
-    /**
-     * Reset the connection and wait for it to complete.
-     * TODO: Remove when all callers only need the asynchronous
-     * reset defined above.
-     */
-    public void resetSynchronously() {
-        ResetSynchronouslyLock lockObj = new ResetSynchronouslyLock();
-        synchronized(lockObj) {
-            sendMessage(obtainMessage(EVENT_RESET, new DisconnectParams(lockObj)));
-            try {
-                lockObj.wait();
-            } catch (InterruptedException e) {
-                log("blockingReset: unexpected interrupted of wait()");
-            }
-        }
-    }
-
-    /**
-     * Connect to the apn and return an AsyncResult in onCompletedMsg.
+     * Bring up a connection to the apn and return an AsyncResult in onCompletedMsg.
      * Used for cellular networks that use Acesss Point Names (APN) such
      * as GSM networks.
      *
      * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
      *        With AsyncResult.userObj set to the original msg.obj,
      *        AsyncResult.result = FailCause and AsyncResult.exception = Exception().
-     * @param apn is the Access Point Name to connect to
+     * @param apn is the Access Point Name to bring up a connection to
      */
-    public void connect(Message onCompletedMsg, ApnSetting apn) {
+    public void bringUp(Message onCompletedMsg, ApnSetting apn) {
         sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(apn, onCompletedMsg)));
     }
 
     /**
-     * Connect to the apn and return an AsyncResult in onCompletedMsg.
-     *
-     * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
-     *        With AsyncResult.userObj set to the original msg.obj,
-     *        AsyncResult.result = FailCause and AsyncResult.exception = Exception().
-     */
-    public void connect(Message onCompletedMsg) {
-        sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(null, onCompletedMsg)));
-    }
-
-    /**
-     * Disconnect from the network.
+     * Tear down the connection through the apn on the network.
      *
      * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
      *        With AsyncResult.userObj set to the original msg.obj.
      */
-    public void disconnect(String reason, Message onCompletedMsg) {
+    public void tearDown(String reason, Message onCompletedMsg) {
         sendMessage(obtainMessage(EVENT_DISCONNECT, new DisconnectParams(reason, onCompletedMsg)));
     }
-
-    // ****** The following are used for debugging.
-
-    /**
-     * TODO: This should be an asynchronous call and we wouldn't
-     * have to use handle the notification in the DcInactiveState.enter.
-     *
-     * @return true if the state machine is in the inactive state.
-     */
-    public boolean isInactive() {
-        boolean retVal = getCurrentState() == mInactiveState;
-        return retVal;
-    }
-
-    /**
-     * TODO: This should be an asynchronous call and we wouldn't
-     * have to use handle the notification in the DcActiveState.enter.
-     *
-     * @return true if the state machine is in the active state.
-     */
-    public boolean isActive() {
-        boolean retVal = getCurrentState() == mActiveState;
-        return retVal;
-    }
-
-    /**
-     * Return the LinkProperties for the connection.
-     *
-     * @return a copy of the LinkProperties, is never null.
-     */
-    public LinkProperties getLinkProperties() {
-        return new LinkProperties(mLinkProperties);
-    }
-
-    /**
-     * A capability is an Integer/String pair, the capabilities
-     * are defined in the class LinkSocket#Key.
-     *
-     * @return a copy of this connections capabilities, may be empty but never null.
-     */
-    public LinkCapabilities getLinkCapabilities() {
-        return new LinkCapabilities(mCapabilities);
-    }
-
-    /**
-     * @return the current state as a string.
-     */
-    public String getStateAsString() {
-        String retVal = getCurrentState().getName();
-        return retVal;
-    }
-
-    /**
-     * @return the time of when this connection was created.
-     */
-    public long getConnectionTime() {
-        return createTime;
-    }
-
-    /**
-     * @return the time of the last failure.
-     */
-    public long getLastFailTime() {
-        return lastFailTime;
-    }
-
-    /**
-     * @return the last cause of failure.
-     */
-    public FailCause getLastFailCause() {
-        return lastFailCause;
-    }
-
-    /**
-     * @return the current ApnSetting
-     */
-    public ApnSetting getApn() {
-        return mApn;
-    }
-
-    public int getCid() {
-        return cid;
-    }
 }
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionAc.java b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
new file mode 100644
index 0000000..a9796dd
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2011 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.util.AsyncChannel;
+import com.android.internal.util.Protocol;
+
+import android.net.LinkCapabilities;
+import android.net.LinkProperties;
+import android.net.ProxyProperties;
+import android.os.Message;
+
+/**
+ * AsyncChannel to a DataConnection
+ */
+public class DataConnectionAc extends AsyncChannel {
+    private static final boolean DBG = true;
+    private String mLogTag;
+
+    public DataConnection dataConnection;
+
+    public static final int BASE = Protocol.BASE_DATA_CONNECTION_AC;
+
+    public static final int REQ_IS_INACTIVE = BASE + 0;
+    public static final int RSP_IS_INACTIVE = BASE + 1;
+
+    public static final int REQ_GET_CID = BASE + 2;
+    public static final int RSP_GET_CID = BASE + 3;
+
+    public static final int REQ_GET_APNSETTING = BASE + 4;
+    public static final int RSP_GET_APNSETTING = BASE + 5;
+
+    public static final int REQ_GET_LINK_PROPERTIES = BASE + 6;
+    public static final int RSP_GET_LINK_PROPERTIES = BASE + 7;
+
+    public static final int REQ_SET_LINK_PROPERTIES_HTTP_PROXY = BASE + 8;
+    public static final int RSP_SET_LINK_PROPERTIES_HTTP_PROXY = BASE + 9;
+
+    public static final int REQ_GET_LINK_CAPABILITIES = BASE + 10;
+    public static final int RSP_GET_LINK_CAPABILITIES = BASE + 11;
+
+    public static final int REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE = BASE + 12;
+    public static final int RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE = BASE + 13;
+
+    public static final int REQ_RESET = BASE + 14;
+    public static final int RSP_RESET = BASE + 15;
+
+    public DataConnectionAc(DataConnection dc, String logTag) {
+        dataConnection = dc;
+        mLogTag = logTag;
+    }
+
+    /**
+     * Request if the state machine is in the inactive state.
+     * Response {@link #rspIsInactive}
+     */
+    public void reqIsInactive() {
+        sendMessage(REQ_IS_INACTIVE);
+        if (DBG) log("reqIsInactive");
+    }
+
+    /**
+     * Evaluate RSP_IS_INACTIVE.
+     *
+     * @return true if the state machine is in the inactive state.
+     */
+    public boolean rspIsInactive(Message response) {
+        boolean retVal = response.arg1 == 1;
+        if (DBG) log("rspIsInactive=" + retVal);
+        return retVal;
+    }
+
+    /**
+     * @return true if the state machine is in the inactive state.
+     */
+    public boolean isInactiveSync() {
+        Message response = sendMessageSynchronously(REQ_IS_INACTIVE);
+        if ((response != null) && (response.what == RSP_IS_INACTIVE)) {
+            return rspIsInactive(response);
+        } else {
+            log("rspIsInactive error response=" + response);
+            return false;
+        }
+    }
+
+    /**
+     * Request the Connection ID.
+     * Response {@link #rspCid}
+     */
+    public void reqCid() {
+        sendMessage(REQ_GET_CID);
+        if (DBG) log("reqCid");
+    }
+
+    /**
+     * Evaluate a RSP_GET_CID message and return the cid.
+     *
+     * @param response Message
+     * @return connection id or -1 if an error
+     */
+    public int rspCid(Message response) {
+        int retVal = response.arg1;
+        if (DBG) log("rspCid=" + retVal);
+        return retVal;
+    }
+
+    /**
+     * @return connection id or -1 if an error
+     */
+    public int getCidSync() {
+        Message response = sendMessageSynchronously(REQ_GET_CID);
+        if ((response != null) && (response.what == RSP_GET_CID)) {
+            return rspCid(response);
+        } else {
+            log("rspCid error response=" + response);
+            return -1;
+        }
+    }
+
+    /**
+     * Request the connections ApnSetting.
+     * Response {@link #rspApnSetting}
+     */
+    public void reqApnSetting() {
+        sendMessage(REQ_GET_APNSETTING);
+        if (DBG) log("reqApnSetting");
+    }
+
+    /**
+     * Evaluate a RSP_APN_SETTING message and return the ApnSetting.
+     *
+     * @param response Message
+     * @return ApnSetting, maybe null
+     */
+    public ApnSetting rspApnSetting(Message response) {
+        ApnSetting retVal = (ApnSetting) response.obj;
+        if (DBG) log("rspApnSetting=" + retVal);
+        return retVal;
+    }
+
+    /**
+     * Get the connections ApnSetting.
+     *
+     * @return ApnSetting or null if an error
+     */
+    public ApnSetting getApnSettingSync() {
+        Message response = sendMessageSynchronously(REQ_GET_APNSETTING);
+        if ((response != null) && (response.what == RSP_GET_APNSETTING)) {
+            return rspApnSetting(response);
+        } else {
+            log("getApnSetting error response=" + response);
+            return null;
+        }
+    }
+
+    /**
+     * Request the connections LinkProperties.
+     * Response {@link #rspLinkProperties}
+     */
+    public void reqLinkProperties() {
+        sendMessage(REQ_GET_LINK_PROPERTIES);
+        if (DBG) log("reqLinkProperties");
+    }
+
+    /**
+     * Evaluate RSP_GET_LINK_PROPERTIES
+     *
+     * @param response
+     * @return LinkProperties, maybe null.
+     */
+    public LinkProperties rspLinkProperties(Message response) {
+        LinkProperties retVal = (LinkProperties) response.obj;
+        if (DBG) log("rspLinkProperties=" + retVal);
+        return retVal;
+    }
+
+    /**
+     * Get the connections LinkProperties.
+     *
+     * @return LinkProperties or null if an error
+     */
+    public LinkProperties getLinkPropertiesSync() {
+        Message response = sendMessageSynchronously(REQ_GET_LINK_PROPERTIES);
+        if ((response != null) && (response.what == RSP_GET_LINK_PROPERTIES)) {
+            return rspLinkProperties(response);
+        } else {
+            log("getLinkProperties error response=" + response);
+            return null;
+        }
+    }
+
+    /**
+     * Request setting the connections LinkProperties.HttpProxy.
+     * Response RSP_SET_LINK_PROPERTIES when complete.
+     */
+    public void reqSetLinkPropertiesHttpProxy(ProxyProperties proxy) {
+        sendMessage(REQ_SET_LINK_PROPERTIES_HTTP_PROXY, proxy);
+        if (DBG) log("reqSetLinkPropertiesHttpProxy proxy=" + proxy);
+    }
+
+    /**
+     * Set the connections LinkProperties.HttpProxy
+     */
+    public void setLinkPropertiesHttpProxySync(ProxyProperties proxy) {
+        Message response =
+            sendMessageSynchronously(REQ_SET_LINK_PROPERTIES_HTTP_PROXY, proxy);
+        if ((response != null) && (response.what == RSP_SET_LINK_PROPERTIES_HTTP_PROXY)) {
+            if (DBG) log("setLinkPropertiesHttpPoxy ok");
+        } else {
+            log("setLinkPropertiesHttpPoxy error response=" + response);
+        }
+    }
+
+    /**
+     * Request the connections LinkCapabilities.
+     * Response {@link #rspLinkCapabilities}
+     */
+    public void reqLinkCapabilities() {
+        sendMessage(REQ_GET_LINK_CAPABILITIES);
+        if (DBG) log("reqLinkCapabilities");
+    }
+
+    /**
+     * Evaluate RSP_GET_LINK_CAPABILITIES
+     *
+     * @param response
+     * @return LinkCapabilites, maybe null.
+     */
+    public LinkCapabilities rspLinkCapabilities(Message response) {
+        LinkCapabilities retVal = (LinkCapabilities) response.obj;
+        if (DBG) log("rspLinkCapabilities=" + retVal);
+        return retVal;
+    }
+
+    /**
+     * Get the connections LinkCapabilities.
+     *
+     * @return LinkCapabilities or null if an error
+     */
+    public LinkCapabilities getLinkCapabilitiesSync() {
+        Message response = sendMessageSynchronously(REQ_GET_LINK_CAPABILITIES);
+        if ((response != null) && (response.what == RSP_GET_LINK_CAPABILITIES)) {
+            return rspLinkCapabilities(response);
+        } else {
+            log("getLinkCapabilities error response=" + response);
+            return null;
+        }
+    }
+
+    /**
+     * Request the connections LinkCapabilities.
+     * Response RSP_RESET when complete
+     */
+    public void reqReset() {
+        sendMessage(REQ_RESET);
+        if (DBG) log("reqReset");
+    }
+
+    /**
+     * Reset the connection and wait for it to complete.
+     */
+    public void resetSync() {
+        Message response = sendMessageSynchronously(REQ_RESET);
+        if ((response != null) && (response.what == RSP_RESET)) {
+            if (DBG) log("restSync ok");
+        } else {
+            if (DBG) log("restSync error response=" + response);
+        }
+    }
+
+    private void log(String s) {
+        android.util.Log.d(mLogTag, "DataConnectionAc " + s);
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 01ac95f..244f35e 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -22,7 +22,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
-import android.net.IConnectivityManager;
 import android.net.LinkCapabilities;
 import android.net.LinkProperties;
 import android.net.NetworkInfo;
@@ -32,7 +31,6 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.Messenger;
-import android.os.ServiceManager;
 import android.preference.PreferenceManager;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
@@ -40,6 +38,9 @@
 import android.util.Log;
 
 import com.android.internal.R;
+import com.android.internal.telephony.DataConnection.FailCause;
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -91,38 +92,39 @@
     public static String EXTRA_MESSENGER = "EXTRA_MESSENGER";
 
     /***** Event Codes *****/
-    protected static final int EVENT_DATA_SETUP_COMPLETE = 1;
-    protected static final int EVENT_RADIO_AVAILABLE = 3;
-    protected static final int EVENT_RECORDS_LOADED = 4;
-    protected static final int EVENT_TRY_SETUP_DATA = 5;
-    protected static final int EVENT_DATA_STATE_CHANGED = 6;
-    protected static final int EVENT_POLL_PDP = 7;
-    protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 12;
-    protected static final int EVENT_VOICE_CALL_STARTED = 14;
-    protected static final int EVENT_VOICE_CALL_ENDED = 15;
-    protected static final int EVENT_DATA_CONNECTION_DETACHED = 19;
-    protected static final int EVENT_LINK_STATE_CHANGED = 20;
-    protected static final int EVENT_ROAMING_ON = 21;
-    protected static final int EVENT_ROAMING_OFF = 22;
-    protected static final int EVENT_ENABLE_NEW_APN = 23;
-    protected static final int EVENT_RESTORE_DEFAULT_APN = 24;
-    protected static final int EVENT_DISCONNECT_DONE = 25;
-    protected static final int EVENT_DATA_CONNECTION_ATTACHED = 26;
-    protected static final int EVENT_START_NETSTAT_POLL = 27;
-    protected static final int EVENT_START_RECOVERY = 28;
-    protected static final int EVENT_APN_CHANGED = 29;
-    protected static final int EVENT_CDMA_DATA_DETACHED = 30;
-    protected static final int EVENT_NV_READY = 31;
-    protected static final int EVENT_PS_RESTRICT_ENABLED = 32;
-    protected static final int EVENT_PS_RESTRICT_DISABLED = 33;
-    public static final int EVENT_CLEAN_UP_CONNECTION = 34;
-    protected static final int EVENT_CDMA_OTA_PROVISION = 35;
-    protected static final int EVENT_RESTART_RADIO = 36;
-    protected static final int EVENT_SET_INTERNAL_DATA_ENABLE = 37;
-    protected static final int EVENT_RESET_DONE = 38;
-    public static final int CMD_SET_DATA_ENABLE = 39;
-    public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = 40;
-    public static final int CMD_SET_DEPENDENCY_MET = 41;
+    protected static final int BASE = Protocol.BASE_DATA_CONNECTION_TRACKER;
+    protected static final int EVENT_DATA_SETUP_COMPLETE = BASE + 0;
+    protected static final int EVENT_RADIO_AVAILABLE = BASE + 1;
+    protected static final int EVENT_RECORDS_LOADED = BASE + 2;
+    protected static final int EVENT_TRY_SETUP_DATA = BASE + 3;
+    protected static final int EVENT_DATA_STATE_CHANGED = BASE + 4;
+    protected static final int EVENT_POLL_PDP = BASE + 5;
+    protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = BASE + 6;
+    protected static final int EVENT_VOICE_CALL_STARTED = BASE + 7;
+    protected static final int EVENT_VOICE_CALL_ENDED = BASE + 8;
+    protected static final int EVENT_DATA_CONNECTION_DETACHED = BASE + 9;
+    protected static final int EVENT_LINK_STATE_CHANGED = BASE + 10;
+    protected static final int EVENT_ROAMING_ON = BASE + 11;
+    protected static final int EVENT_ROAMING_OFF = BASE + 12;
+    protected static final int EVENT_ENABLE_NEW_APN = BASE + 13;
+    protected static final int EVENT_RESTORE_DEFAULT_APN = BASE + 14;
+    protected static final int EVENT_DISCONNECT_DONE = BASE + 15;
+    protected static final int EVENT_DATA_CONNECTION_ATTACHED = BASE + 16;
+    protected static final int EVENT_START_NETSTAT_POLL = BASE + 17;
+    protected static final int EVENT_START_RECOVERY = BASE + 18;
+    protected static final int EVENT_APN_CHANGED = BASE + 19;
+    protected static final int EVENT_CDMA_DATA_DETACHED = BASE + 20;
+    protected static final int EVENT_NV_READY = BASE + 21;
+    protected static final int EVENT_PS_RESTRICT_ENABLED = BASE + 22;
+    protected static final int EVENT_PS_RESTRICT_DISABLED = BASE + 23;
+    public static final int EVENT_CLEAN_UP_CONNECTION = BASE + 24;
+    protected static final int EVENT_CDMA_OTA_PROVISION = BASE + 25;
+    protected static final int EVENT_RESTART_RADIO = BASE + 26;
+    protected static final int EVENT_SET_INTERNAL_DATA_ENABLE = BASE + 27;
+    protected static final int EVENT_RESET_DONE = BASE + 28;
+    public static final int CMD_SET_DATA_ENABLE = BASE + 29;
+    public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = BASE + 30;
+    public static final int CMD_SET_DEPENDENCY_MET = BASE + 31;
 
     /***** Constants *****/
 
@@ -142,6 +144,9 @@
 
     public static final String APN_TYPE_KEY = "apnType";
 
+    /** Delay between APN attempts */
+    protected static final int APN_DELAY_MILLIS = 5000;
+
     // responds to the setInternalDataEnabled call - used internally to turn off data
     // for example during emergency calls
     protected boolean mInternalDataEnabled = true;
@@ -201,6 +206,19 @@
     //       getActionIntentReconnectAlarm.
     protected static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason";
 
+    // Used for debugging. Send the INTENT with an optional counter value with the number
+    // of times the setup is to fail before succeeding. If the counter isn't passed the
+    // setup will fail once. Example fail two times with FailCause.SIGNAL_LOST(-3)
+    // adb shell am broadcast \
+    //  -a com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter \
+    //  --ei fail_data_setup_counter 3 --ei fail_data_setup_fail_cause -3
+    protected static final String INTENT_SET_FAIL_DATA_SETUP_COUNTER =
+        "com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter";
+    protected static final String FAIL_DATA_SETUP_COUNTER = "fail_data_setup_counter";
+    protected int mFailDataSetupCounter = 0;
+    protected static final String FAIL_DATA_SETUP_FAIL_CAUSE = "fail_data_setup_fail_cause";
+    protected FailCause mFailDataSetupFailCause = FailCause.ERROR_UNSPECIFIED;
+
     // member variables
     protected PhoneBase mPhone;
     protected Activity mActivity = Activity.NONE;
@@ -227,7 +245,7 @@
     /** indication of our availability (preconditions to trysetupData are met) **/
     protected boolean mAvailability = false;
 
-    // When false we will not auto attach and manully attaching is required.
+    // When false we will not auto attach and manually attaching is required.
     protected boolean mAutoAttachOnCreation = false;
 
     // State of screen
@@ -235,12 +253,6 @@
     //        really a lower power mode")
     protected boolean mIsScreenOn = true;
 
-    /** The link properties (dns, gateway, ip, etc) */
-    protected LinkProperties mLinkProperties = new LinkProperties();
-
-    /** The link capabilities */
-    protected LinkCapabilities mLinkCapabilities = new LinkCapabilities();
-
     /** Allows the generation of unique Id's for DataConnection objects */
     protected AtomicInteger mUniqueIdGenerator = new AtomicInteger(0);
 
@@ -248,6 +260,10 @@
     protected HashMap<Integer, DataConnection> mDataConnections =
         new HashMap<Integer, DataConnection>();
 
+    /** The data connection async channels */
+    protected HashMap<Integer, DataConnectionAc> mDataConnectionAsyncChannels =
+        new HashMap<Integer, DataConnectionAc>();
+
     /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */
     protected HashMap<String, Integer> mApnToDataConnectionId =
                                     new HashMap<String, Integer>();
@@ -267,7 +283,6 @@
     /** Is packet service restricted by network */
     protected boolean mIsPsRestricted = false;
 
-
     /* Once disposed dont handle any messages */
     protected boolean mIsDisposed = false;
 
@@ -277,6 +292,7 @@
         public void onReceive(Context context, Intent intent)
         {
             String action = intent.getAction();
+            if (DBG) log("onReceive: action=" + action);
             if (action.equals(Intent.ACTION_SCREEN_ON)) {
                 mIsScreenOn = true;
                 stopNetStatPoll();
@@ -302,10 +318,36 @@
                     // quit and won't report disconnected until next enabling.
                     mIsWifiConnected = false;
                 }
+            } else if (action.equals(INTENT_SET_FAIL_DATA_SETUP_COUNTER)) {
+                mFailDataSetupCounter = intent.getIntExtra(FAIL_DATA_SETUP_COUNTER, 1);
+                mFailDataSetupFailCause = FailCause.fromInt(
+                        intent.getIntExtra(FAIL_DATA_SETUP_FAIL_CAUSE,
+                                                    FailCause.ERROR_UNSPECIFIED.getErrorCode()));
+                if (DBG) log("set mFailDataSetupCounter=" + mFailDataSetupCounter +
+                        " mFailDataSetupFailCause=" + mFailDataSetupFailCause);
             }
         }
     };
 
+    protected boolean isDataSetupCompleteOk(AsyncResult ar) {
+        if (ar.exception != null) {
+            if (DBG) log("isDataSetupCompleteOk return false, ar.result=" + ar.result);
+            return false;
+        }
+        if (mFailDataSetupCounter <= 0) {
+            if (DBG) log("isDataSetupCompleteOk return true");
+            return true;
+        }
+        ar.result = mFailDataSetupFailCause;
+        if (DBG) {
+            log("isDataSetupCompleteOk return false" +
+                    " mFailDataSetupCounter=" + mFailDataSetupCounter +
+                    " mFailDataSetupFailCause=" + mFailDataSetupFailCause);
+        }
+        mFailDataSetupCounter -= 1;
+        return false;
+    }
+
     protected void onActionIntentReconnectAlarm(Intent intent) {
         String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
         if (mState == State.FAILED) {
@@ -331,6 +373,7 @@
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
         filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        filter.addAction(INTENT_SET_FAIL_DATA_SETUP_COUNTER);
 
         mDataEnabled = Settings.Secure.getInt(mPhone.getContext().getContentResolver(),
                 Settings.Secure.MOBILE_DATA, 1) == 1;
@@ -351,6 +394,10 @@
     }
 
     public void dispose() {
+        for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
+            dcac.disconnect();
+        }
+        mDataConnectionAsyncChannels.clear();
         mIsDisposed = true;
         mPhone.getContext().unregisterReceiver(this.mIntentReceiver);
     }
@@ -463,7 +510,13 @@
     @Override
     public void handleMessage(Message msg) {
         switch (msg.what) {
-
+            case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
+                log("DISCONNECTED_CONNECTED: msg=" + msg);
+                DataConnectionAc dcac = (DataConnectionAc) msg.obj;
+                mDataConnectionAsyncChannels.remove(dcac.dataConnection.getDataConnectionId());
+                dcac.disconnected();
+                break;
+            }
             case EVENT_ENABLE_NEW_APN:
                 onEnableApn(msg.arg1, msg.arg2);
                 break;
@@ -528,19 +581,20 @@
                 break;
             }
             case EVENT_RESET_DONE: {
+                if (DBG) log("EVENT_RESET_DONE");
                 onResetDone((AsyncResult) msg.obj);
                 break;
             }
             case CMD_SET_DATA_ENABLE: {
-                log("CMD_SET_DATA_ENABLE msg=" + msg);
                 boolean enabled = (msg.arg1 == ENABLED) ? true : false;
+                if (DBG) log("CMD_SET_DATA_ENABLE enabled=" + enabled);
                 onSetDataEnabled(enabled);
                 break;
             }
 
             case CMD_SET_DEPENDENCY_MET: {
-                log("CMD_SET_DEPENDENCY_MET msg=" + msg);
                 boolean met = (msg.arg1 == ENABLED) ? true : false;
+                if (DBG) log("CMD_SET_DEPENDENCY_MET met=" + met);
                 Bundle bundle = msg.getData();
                 if (bundle != null) {
                     String apnType = (String)bundle.get(APN_TYPE_KEY);
@@ -552,7 +606,7 @@
             }
 
             default:
-                Log.e("DATA", "Unidentified event = " + msg.what);
+                Log.e("DATA", "Unidentified event msg=" + msg);
                 break;
         }
     }
@@ -618,7 +672,8 @@
     protected LinkProperties getLinkProperties(String apnType) {
         int id = apnTypeToId(apnType);
         if (isApnIdEnabled(id)) {
-            return new LinkProperties(mLinkProperties);
+            DataConnectionAc dcac = mDataConnectionAsyncChannels.get(id);
+            return dcac.getLinkPropertiesSync();
         } else {
             return new LinkProperties();
         }
@@ -627,33 +682,13 @@
     protected LinkCapabilities getLinkCapabilities(String apnType) {
         int id = apnTypeToId(apnType);
         if (isApnIdEnabled(id)) {
-            return new LinkCapabilities(mLinkCapabilities);
+            DataConnectionAc dcac = mDataConnectionAsyncChannels.get(id);
+            return dcac.getLinkCapabilitiesSync();
         } else {
             return new LinkCapabilities();
         }
     }
 
-    /**
-     * Return the LinkProperties for the connection.
-     *
-     * @param connection
-     * @return a copy of the LinkProperties, is never null.
-     */
-    protected LinkProperties getLinkProperties(DataConnection connection) {
-        return connection.getLinkProperties();
-    }
-
-    /**
-     * A capability is an Integer/String pair, the capabilities
-     * are defined in the class LinkSocket#Key.
-     *
-     * @param connection
-     * @return a copy of this connections capabilities, may be empty but never null.
-     */
-    protected LinkCapabilities getLinkCapabilities(DataConnection connection) {
-        return connection.getLinkCapabilities();
-    }
-
     // tell all active apns of the current condition
     protected void notifyDataConnection(String reason) {
         for (int id = 0; id < APN_NUM_TYPES; id++) {
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index c052e5142..490051d 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -3024,7 +3024,7 @@
             dataCall.active = p.readInt();
             dataCall.type = p.readString();
             String addresses = p.readString();
-            if (TextUtils.isEmpty(addresses)) {
+            if (!TextUtils.isEmpty(addresses)) {
                 dataCall.addresses = addresses.split(" ");
             }
         } else {
@@ -3033,7 +3033,8 @@
             dataCall.active = p.readInt();
             dataCall.type = p.readString();
             dataCall.ifname = p.readString();
-            if (TextUtils.isEmpty(dataCall.ifname)) {
+            if ((dataCall.status == DataConnection.FailCause.NONE.getErrorCode()) &&
+                    TextUtils.isEmpty(dataCall.ifname)) {
               throw new RuntimeException("getDataCallState, no ifname");
             }
             String addresses = p.readString();
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
index e299d4a..d55f346 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
@@ -20,7 +20,6 @@
 import android.util.Log;
 
 import com.android.internal.telephony.DataConnection;
-import com.android.internal.telephony.DataConnection.FailCause;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.RetryManager;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index dc85017..f325812 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -37,10 +37,12 @@
 import com.android.internal.telephony.DataCallState;
 import com.android.internal.telephony.DataConnection.FailCause;
 import com.android.internal.telephony.DataConnection;
+import com.android.internal.telephony.DataConnectionAc;
 import com.android.internal.telephony.DataConnectionTracker;
 import com.android.internal.telephony.EventLogTags;
 import com.android.internal.telephony.RetryManager;
 import com.android.internal.telephony.Phone;
+import com.android.internal.util.AsyncChannel;
 
 import java.util.ArrayList;
 
@@ -52,9 +54,6 @@
 
     private CDMAPhone mCdmaPhone;
 
-    //useful for debugging
-    boolean mFailNextConnect = false;
-
     /** The DataConnection being setup */
     private CdmaDataConnection mPendingDataConnection;
 
@@ -297,14 +296,18 @@
         boolean notificationDeferred = false;
         for (DataConnection conn : mDataConnections.values()) {
             if(conn != null) {
+                DataConnectionAc dcac =
+                    mDataConnectionAsyncChannels.get(conn.getDataConnectionId());
                 if (tearDown) {
                     if (DBG) log("cleanUpConnection: teardown, call conn.disconnect");
-                    conn.disconnect(reason, obtainMessage(EVENT_DISCONNECT_DONE,
+                    conn.tearDown(reason, obtainMessage(EVENT_DISCONNECT_DONE,
                             conn.getDataConnectionId(), 0, reason));
                     notificationDeferred = true;
                 } else {
                     if (DBG) log("cleanUpConnection: !tearDown, call conn.resetSynchronously");
-                    conn.resetSynchronously();
+                    if (dcac != null) {
+                        dcac.resetSync();
+                    }
                     notificationDeferred = false;
                 }
             }
@@ -319,11 +322,13 @@
     }
 
     private CdmaDataConnection findFreeDataConnection() {
-        for (DataConnection dc : mDataConnections.values()) {
-            if (dc.isInactive()) {
-                return (CdmaDataConnection) dc;
+        for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
+            if (dcac.isInactiveSync()) {
+                log("found free GsmDataConnection");
+                return (CdmaDataConnection) dcac.dataConnection;
             }
         }
+        log("NO free CdmaDataConnection");
         return null;
     }
 
@@ -349,12 +354,12 @@
         }
         mActiveApn = new ApnSetting(apnId, "", "", "", "", "", "", "", "", "",
                                     "", 0, types, "IP", "IP");
-        if (DBG) log("setupData: mActiveApn=" + mActiveApn);
+        if (DBG) log("call conn.bringUp mActiveApn=" + mActiveApn);
 
         Message msg = obtainMessage();
         msg.what = EVENT_DATA_SETUP_COMPLETE;
         msg.obj = reason;
-        conn.connect(msg, mActiveApn);
+        conn.bringUp(msg, mActiveApn);
 
         setState(State.INITING);
         notifyDataConnection(reason);
@@ -652,12 +657,8 @@
             reason = (String) ar.userObj;
         }
 
-        if (ar.exception == null) {
-            // TODO: We should clear LinkProperties/Capabilities when torn down or disconnected
-            mLinkProperties = getLinkProperties(mPendingDataConnection);
-            mLinkCapabilities = getLinkCapabilities(mPendingDataConnection);
-
-            // everything is setup
+        if (isDataSetupCompleteOk(ar)) {
+            // Everything is setup
             notifyDefaultData(reason);
         } else {
             FailCause cause = (FailCause) (ar.result);
@@ -700,7 +701,8 @@
         notifyDataConnection(reason);
         mActiveApn = null;
         if (retryAfterDisconnected(reason)) {
-          trySetupData(reason);
+          // Wait a bit before trying, so we're not tying up RIL command channel.
+          sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason), APN_DELAY_MILLIS);
       }
     }
 
@@ -767,6 +769,16 @@
             int id = mUniqueIdGenerator.getAndIncrement();
             dataConn = CdmaDataConnection.makeDataConnection(mCdmaPhone, id, rm);
             mDataConnections.put(id, dataConn);
+            DataConnectionAc dcac = new DataConnectionAc(dataConn, LOG_TAG);
+            int status = dcac.fullyConnectSync(mPhone.getContext(), this, dataConn.getHandler());
+            if (status == AsyncChannel.STATUS_SUCCESSFUL) {
+                log("Fully connected");
+                mDataConnectionAsyncChannels.put(dcac.dataConnection.getDataConnectionId(), dcac);
+            } else {
+                log("Could not connect to dcac.dataConnection=" + dcac.dataConnection +
+                        " status=" + status);
+            }
+
         }
     }
 
@@ -897,6 +909,7 @@
 
     @Override
     public void handleMessage (Message msg) {
+        if (DBG) log("CdmaDCT handleMessage msg=" + msg);
 
         if (!mPhone.mIsTheCurrentActivePhone || mIsDisposed) {
             log("Ignore CDMA msgs since CDMA phone is inactive");
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
index 545ad8a..9695344 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
@@ -21,7 +21,6 @@
 import android.util.Patterns;
 import android.text.TextUtils;
 
-import com.android.internal.telephony.ApnSetting;
 import com.android.internal.telephony.DataConnection;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneBase;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 8e675fc..d3e659a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -53,6 +53,7 @@
 import com.android.internal.telephony.ApnSetting;
 import com.android.internal.telephony.DataCallState;
 import com.android.internal.telephony.DataConnection;
+import com.android.internal.telephony.DataConnectionAc;
 import com.android.internal.telephony.DataConnectionTracker;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneBase;
@@ -60,6 +61,7 @@
 import com.android.internal.telephony.EventLogTags;
 import com.android.internal.telephony.DataConnection.FailCause;
 import com.android.internal.telephony.RILConstants;
+import com.android.internal.util.AsyncChannel;
 
 import java.io.IOException;
 import java.net.InetAddress;
@@ -99,11 +101,6 @@
     // call reRegisterNetwork, or pingTest succeeds.
     private int mPdpResetCount = 0;
 
-    /** Delay between APN attempts */
-    protected static final int APN_DELAY_MILLIS = 5000;
-
-    //useful for debugging
-    boolean mFailNextConnect = false;
 
     //***** Constants
 
@@ -119,7 +116,7 @@
 
     @Override
     protected void onActionIntentReconnectAlarm(Intent intent) {
-        log("GPRS reconnect alarm. Previous state was " + mState);
+        if (DBG) log("GPRS reconnect alarm. Previous state was " + mState);
 
         String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
         String type = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE);
@@ -224,7 +221,7 @@
         boolean possible = (isDataAllowed()
                 && !(getAnyDataEnabled() && (getOverallState() == State.FAILED)));
         if (!possible && DBG && isDataAllowed()) {
-            log("Data not possible.  No coverage: dataState = " + getOverallState());
+            if (DBG) log("Data not possible.  No coverage: dataState = " + getOverallState());
         }
         return possible;
     }
@@ -319,10 +316,10 @@
     protected LinkProperties getLinkProperties(String apnType) {
         ApnContext apnContext = mApnContexts.get(apnType);
         if (apnContext != null) {
-            DataConnection dataConnection = apnContext.getDataConnection();
-            if (dataConnection != null) {
-                if (DBG) log("get active pdp is not null, return link properites for " + apnType);
-                return dataConnection.getLinkProperties();
+            DataConnectionAc dcac = apnContext.getDataConnectionAc();
+            if (dcac != null) {
+                if (DBG) log("return link properites for " + apnType);
+                return dcac.getLinkPropertiesSync();
             }
         }
         if (DBG) log("return new LinkProperties");
@@ -333,10 +330,10 @@
     protected LinkCapabilities getLinkCapabilities(String apnType) {
         ApnContext apnContext = mApnContexts.get(apnType);
         if (apnContext!=null) {
-            DataConnection dataConnection = apnContext.getDataConnection();
-            if (dataConnection != null) {
+            DataConnectionAc dataConnectionAc = apnContext.getDataConnectionAc();
+            if (dataConnectionAc != null) {
                 if (DBG) log("get active pdp is not null, return link Capabilities for " + apnType);
-                return dataConnection.getLinkCapabilities();
+                return dataConnectionAc.getLinkCapabilitiesSync();
             }
         }
         if (DBG) log("return new LinkCapabilities");
@@ -424,6 +421,7 @@
         }
 
         if (!isAnyEnabled) { // Nothing enabled. return IDLE.
+            if (DBG) log( "overall state is IDLE");
             return State.IDLE;
         }
 
@@ -450,34 +448,34 @@
      */
     @Override
     public synchronized int enableApnType(String apnType) {
-        if (DBG) log("calling enableApnType with type:" + apnType);
-
         ApnContext apnContext = mApnContexts.get(apnType);
         if (apnContext == null || !isApnTypeAvailable(apnType)) {
-            if (DBG) log("type not available");
+            if (DBG) log("enableApnType: " + apnType + " is type not available");
             return Phone.APN_TYPE_NOT_AVAILABLE;
         }
 
         // If already active, return
-        log("enableApnType(" + apnType + ")" + ", mState(" + apnContext.getState() + ")");
+        if (DBG) log("enableApnType: " + apnType + " mState(" + apnContext.getState() + ")");
 
         if (apnContext.getState() == State.INITING) {
-            if (DBG) log("return APN_REQUEST_STARTED");
+            if (DBG) log("enableApnType: return APN_REQUEST_STARTED");
             return Phone.APN_REQUEST_STARTED;
         }
         else if (apnContext.getState() == State.CONNECTED) {
-            if (DBG) log("return APN_ALREADY_ACTIVE");
+            if (DBG) log("enableApnType: return APN_ALREADY_ACTIVE");
             return Phone.APN_ALREADY_ACTIVE;
         }
         else if (apnContext.getState() == State.DISCONNECTING) {
-            if (DBG) log("requested APN while disconnecting");
+            if (DBG) log("enableApnType: while disconnecting, return APN_REQUEST_STARTED");
             apnContext.setPendingAction(ApnContext.PENDING_ACTION_RECONNECT);
             return Phone.APN_REQUEST_STARTED;
         }
 
-        if (DBG) log("new apn request for type " + apnType + " is to be handled");
         setEnabled(apnTypeToId(apnType), true);
-        if (DBG) log("return APN_REQUEST_STARTED");
+        if (DBG) {
+            log("enableApnType: new apn request for type " + apnType +
+                    " return APN_REQUEST_STARTED");
+        }
         return Phone.APN_REQUEST_STARTED;
     }
 
@@ -502,7 +500,7 @@
 
     @Override
     public synchronized int disableApnType(String type) {
-        if (DBG) log("calling disableApnType with type:" + type);
+        if (DBG) log("disableApnType:" + type);
         ApnContext apnContext = mApnContexts.get(type);
 
         if (apnContext != null) {
@@ -515,18 +513,19 @@
                 apnContext.setReason(Phone.REASON_DATA_DISABLED);
                 msg.obj = apnContext;
                 sendMessage(msg);
-                if (DBG) log("return APN_REQUEST_STARTED");
+                if (DBG) log("diableApnType: return APN_REQUEST_STARTED");
                 return Phone.APN_REQUEST_STARTED;
             } else {
-                if (DBG) log("return APN_ALREADY_INACTIVE");
+                if (DBG) log("disableApnType: return APN_ALREADY_INACTIVE");
                 apnContext.setEnabled(false);
                 apnContext.setDataConnection(null);
                 return Phone.APN_ALREADY_INACTIVE;
             }
 
         } else {
-            if (DBG)
-                log("no apn context was found, return APN_REQUEST_FAILED");
+            if (DBG) {
+                log("disableApnType: no apn context was found, return APN_REQUEST_FAILED");
+            }
             return Phone.APN_REQUEST_FAILED;
         }
     }
@@ -583,12 +582,15 @@
          * We presently believe it is unnecessary to tear down the PDP context
          * when GPRS detaches, but we should stop the network polling.
          */
+        if (DBG) log ("onDataConnectionDetached: stop polling and notify detached");
         stopNetStatPoll();
         notifyDataConnection(Phone.REASON_DATA_DETACHED);
     }
 
     private void onDataConnectionAttached() {
+        if (DBG) log("onDataConnectionAttached");
         if (getOverallState() == State.CONNECTED) {
+            if (DBG) log("onDataConnectionAttached: start polling notify attached");
             startNetStatPoll();
             notifyDataConnection(Phone.REASON_DATA_ATTACHED);
         }
@@ -624,11 +626,40 @@
             }
             if (mIsPsRestricted) reason += " - mIsPsRestricted= true";
             if (!desiredPowerState) reason += " - desiredPowerState= false";
-            log("Data not allowed due to" + reason);
+            if (DBG) log("isDataAllowed: not allowed due to" + reason);
         }
         return allowed;
     }
 
+    /**
+     * Release the apnContext
+     *
+     * @param apnContext
+     * @param tearDown
+     * @return refCount
+     */
+    private int releaseApnContext(ApnContext apnContext, boolean tearDown) {
+        if (apnContext == null) {
+            if (DBG) loge("releaseApnContext: apnContext null should not happen, ignore");
+            return -1;
+        }
+        DataConnection dc = apnContext.getDataConnection();
+        if (dc == null) {
+            if (DBG) loge("releaseApnContext: apnContext dc == null should not happen, ignore");
+            return -1;
+        }
+        int refCount = dc.decAndGetRefCount();
+        if (DBG) log("releaseApnContext: dec refCount=" + refCount + " tearDown=" + tearDown);
+        if (tearDown && (refCount == 0)) {
+            if (DBG) log("releaseApnContext: tearing down");
+            Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
+            apnContext.getDataConnection().tearDown(apnContext.getReason(), msg);
+        }
+        apnContext.setDataConnection(null);
+        apnContext.setDataConnectionAc(null);
+        return refCount;
+    }
+
     private void setupDataOnReadyApns(String reason) {
         // Only check for default APN state
         for (ApnContext apnContext : mApnContexts.values()) {
@@ -651,9 +682,8 @@
 
     private boolean trySetupData(String reason, String type) {
         if (DBG) {
-            log("***trySetupData for type:" + type +
-                    " due to " + (reason == null ? "(unspecified)" : reason) +
-                    " isPsRestricted=" + mIsPsRestricted);
+            log("trySetupData: " + type + " due to " + (reason == null ? "(unspecified)" : reason)
+                    + " isPsRestricted=" + mIsPsRestricted);
         }
 
         if (type == null) {
@@ -663,18 +693,16 @@
         ApnContext apnContext = mApnContexts.get(type);
 
         if (apnContext == null ){
-            if (DBG) log("new apn context for type:" + type);
+            if (DBG) log("trySetupData new apn context for type:" + type);
             apnContext = new ApnContext(type, LOG_TAG);
             mApnContexts.put(type, apnContext);
         }
         apnContext.setReason(reason);
 
         return trySetupData(apnContext);
-
     }
 
     private boolean trySetupData(ApnContext apnContext) {
-
         if (DBG) {
             log("trySetupData for type:" + apnContext.getApnType() +
                     " due to " + apnContext.getReason());
@@ -687,7 +715,7 @@
             apnContext.setState(State.CONNECTED);
             mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
 
-            log("(fix?) We're on the simulator; assuming data is connected");
+            log("trySetupData: (fix?) We're on the simulator; assuming data is connected");
             return true;
         }
 
@@ -699,13 +727,15 @@
             if (apnContext.getState() == State.IDLE) {
                 ArrayList<ApnSetting> waitingApns = buildWaitingApns(apnContext.getApnType());
                 if (waitingApns.isEmpty()) {
-                    if (DBG) log("No APN found");
+                    if (DBG) log("trySetupData: No APN found");
                     notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN, apnContext);
                     notifyOffApnsOfAvailability(apnContext.getReason(), false);
                     return false;
                 } else {
                     apnContext.setWaitingApns(waitingApns);
-                    log ("Create from mAllApns : " + apnListToString(mAllApns));
+                    if (DBG) {
+                        log ("trySetupData: Create from mAllApns : " + apnListToString(mAllApns));
+                    }
                 }
             }
 
@@ -735,7 +765,7 @@
 
         for (ApnContext apnContext : mApnContexts.values()) {
             if (!apnContext.isReady()) {
-                if (DBG) log("notify disconnected for type:" + apnContext.getApnType());
+                if (DBG) log("notifyOffApnOfAvailability type:" + apnContext.getApnType());
                 mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
                                             apnContext.getApnType(),
                                             Phone.DataState.DISCONNECTED);
@@ -753,7 +783,7 @@
      * @param reason reason for the clean up.
      */
     protected void cleanUpAllConnections(boolean tearDown, String reason) {
-        if (DBG) log("Clean up all connections due to " + reason);
+        if (DBG) log("cleanUpAllConnections: tearDown=" + tearDown + " reason=" + reason);
 
         for (ApnContext apnContext : mApnContexts.values()) {
             apnContext.setReason(reason);
@@ -784,11 +814,13 @@
     private void cleanUpConnection(boolean tearDown, ApnContext apnContext) {
 
         if (apnContext == null) {
-            if (DBG) log("apn context is null");
+            if (DBG) log("cleanUpConnection: apn context is null");
             return;
         }
 
-        if (DBG) log("Clean up connection due to " + apnContext.getReason());
+        if (DBG) {
+            log("cleanUpConnection: tearDown=" + tearDown + " reason=" + apnContext.getReason());
+        }
 
         // Clear the reconnect alarm, if set.
         if (apnContext.getReconnectIntent() != null) {
@@ -799,24 +831,26 @@
         }
 
         if (apnContext.getState() == State.IDLE || apnContext.getState() == State.DISCONNECTING) {
-            if (DBG) log("state is in " + apnContext.getState());
+            if (DBG) log("cleanUpConnection: state= " + apnContext.getState());
             return;
         }
 
         if (apnContext.getState() == State.FAILED) {
-            if (DBG) log("state is in FAILED");
+            if (DBG) log("cleanUpConnection: state is in FAILED");
             apnContext.setState(State.IDLE);
             return;
         }
 
         DataConnection conn = apnContext.getDataConnection();
         if (conn != null) {
+            DataConnectionAc dcac = mDataConnectionAsyncChannels.get(conn.getDataConnectionId());
             apnContext.setState(State.DISCONNECTING);
             if (tearDown) {
-                Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
-                conn.disconnect(apnContext.getReason(), msg);
+                releaseApnContext(apnContext, tearDown);
             } else {
-                conn.resetSynchronously();
+                if (dcac != null) {
+                    dcac.resetSync();
+                }
                 apnContext.setState(State.IDLE);
                 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
             }
@@ -871,27 +905,31 @@
     }
 
     private GsmDataConnection findFreeDataConnection() {
-        for (DataConnection dc : mDataConnections.values()) {
-            if (dc.isInactive()) {
-                log("found free GsmDataConnection");
-                return (GsmDataConnection) dc;
+        for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
+            if (dcac.isInactiveSync()) {
+                log("findFreeDataConnection: found free GsmDataConnection");
+                return (GsmDataConnection) dcac.dataConnection;
             }
         }
-        log("NO free GsmDataConnection");
+        log("findFreeDataConnection: NO free GsmDataConnection");
         return null;
     }
 
     protected GsmDataConnection findReadyDataConnection(ApnSetting apn) {
         if (DBG)
-            log("findReadyDataConnection for apn string <" +
+            log("findReadyDataConnection: apn string <" +
                 (apn!=null?(apn.toString()):"null") +">");
-        for (DataConnection conn : mDataConnections.values()) {
-            GsmDataConnection dc = (GsmDataConnection) conn;
-            if (DBG) log("dc apn string <" +
-                         (dc.getApn() != null ? (dc.getApn().toString()) : "null") + ">");
-            if (dc.getApn() != null && apn != null
-                && dc.getApn().toString().equals(apn.toString())) {
-                return dc;
+        if (apn == null) {
+            return null;
+        }
+        for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
+            ApnSetting apnSetting = dcac.getApnSettingSync();
+            if (DBG) {
+                log("findReadyDataConnection: dc apn string <" +
+                         (apnSetting != null ? (apnSetting.toString()) : "null") + ">");
+            }
+            if ((apnSetting != null) && TextUtils.equals(apnSetting.toString(), apn.toString())) {
+                return (GsmDataConnection) dcac.dataConnection;
             }
         }
         return null;
@@ -899,7 +937,7 @@
 
 
     private boolean setupData(ApnContext apnContext) {
-        if (DBG) log("enter setupData!");
+        if (DBG) log("setupData: apnContext=" + apnContext);
         ApnSetting apn;
         GsmDataConnection dc;
 
@@ -920,7 +958,7 @@
         }
 
         if (dc == null) {
-            dc = createDataConnection(apnContext);
+            dc = createDataConnection(apnContext.getApnType());
         }
 
         if (dc == null) {
@@ -928,17 +966,19 @@
             return false;
         }
 
-        apnContext.setApnSetting(apn);
-        apnContext.setDataConnection(dc);
         dc.setProfileId( profileId );
         dc.setActiveApnType(apnContext.getApnType());
+        int refCount = dc.incAndGetRefCount();
+        if (DBG) log("setupData: init dc and apnContext refCount=" + refCount);
+        DataConnectionAc dcac = mDataConnectionAsyncChannels.get(dc.getDataConnectionId());
+        apnContext.setDataConnectionAc(mDataConnectionAsyncChannels.get(dc.getDataConnectionId()));
+        apnContext.setApnSetting(apn);
+        apnContext.setDataConnection(dc);
 
         Message msg = obtainMessage();
         msg.what = EVENT_DATA_SETUP_COMPLETE;
         msg.obj = apnContext;
-
-        if (DBG) log("dc connect!");
-        dc.connect(msg, apn);
+        dc.bringUp(msg, apn);
 
         apnContext.setState(State.INITING);
         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
@@ -981,7 +1021,7 @@
 
         // TODO: It'd be nice to only do this if the changed entrie(s)
         // match the current operator.
-        if (DBG) log("onApnChanged createAllApnList and cleanUpAllConnections");
+        if (DBG) log("onApnChanged: createAllApnList and cleanUpAllConnections");
         createAllApnList();
         cleanUpAllConnections(isConnected, Phone.REASON_APN_CHANGED);
         if (!isConnected) {
@@ -998,25 +1038,30 @@
     private void onDataStateChanged (AsyncResult ar) {
         ArrayList<DataCallState> dataCallStates;
 
+        if (DBG) log("onDataStateChanged(ar) E");
         dataCallStates = (ArrayList<DataCallState>)(ar.result);
 
         if (ar.exception != null) {
             // This is probably "radio not available" or something
             // of that sort. If so, the whole connection is going
             // to come down soon anyway
+            if (DBG) log("onDataStateChanged(ar): exception; likely radio not available, ignore");
             return;
         }
 
         for (ApnContext apnContext : mApnContexts.values()) {
             onDataStateChanged(dataCallStates, apnContext);
         }
+        if (DBG) log("onDataStateChanged(ar) X");
     }
 
     private void onDataStateChanged (ArrayList<DataCallState> dataCallStates,
                                      ApnContext apnContext) {
+        if (DBG) log("onDataStateChanged(dataCallState, apnContext):  apnContext=" + apnContext);
 
         if (apnContext == null) {
             // Should not happen
+            if (DBG) log("onDataStateChanged(dataCallState, apnContext):  ignore apnContext=null");
             return;
         }
 
@@ -1027,28 +1072,37 @@
             // context is still listed with active = false, which
             // makes it hard to distinguish an activating context from
             // an activated-and-then deactivated one.
-            if (!dataCallStatesHasCID(dataCallStates, apnContext.getDataConnection().getCid())) {
+            DataConnectionAc dcac = apnContext.getDataConnectionAc();
+            if (dcac == null) {
+                if (DBG) log("onDataStateChanged(dataCallState, apnContext):  dcac==null BAD NEWS");
+                return;
+            }
+            int cid = dcac.getCidSync();
+            if (!dataCallStatesHasCID(dataCallStates, cid)) {
                 // It looks like the PDP context has deactivated.
                 // Tear everything down and try to reconnect.
 
-                Log.i(LOG_TAG, "PDP connection has dropped. Reconnecting");
-
+                if (DBG) {
+                    log("onDataStateChanged(dataCallStates,apnContext) " +
+                        "PDP connection has dropped. Reconnecting");
+                }
                 // Add an event log when the network drops PDP
-                int cid = getCellLocationId();
-                EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid,
+                int cellLocationId = getCellLocationId();
+                EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cellLocationId,
                         TelephonyManager.getDefault().getNetworkType());
 
                 cleanUpConnection(true, apnContext);
-                return;
             } else if (!dataCallStatesHasActiveCID(dataCallStates,
-                    apnContext.getDataConnection().getCid())) {
+                    apnContext.getDataConnectionAc().getCidSync())) {
 
-                Log.i(LOG_TAG, "PDP connection has dropped (active=false case). "
-                                    + " Reconnecting");
+                if (DBG) {
+                    log("onDataStateChanged(dataCallStates,apnContext) " +
+                        "PDP connection has dropped (active=false case). Reconnecting");
+                }
 
                 // Log the network drop on the event log.
-                int cid = getCellLocationId();
-                EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid,
+                int cellLocationId = getCellLocationId();
+                EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cellLocationId,
                         TelephonyManager.getDefault().getNetworkType());
 
                 cleanUpConnection(true, apnContext);
@@ -1057,9 +1111,10 @@
     }
 
     private void notifyDefaultData(ApnContext apnContext) {
-        if (DBG)
-            log("notifyDefaultData for type: " + apnContext.getApnType()
+        if (DBG) {
+            log("notifyDefaultData: type=" + apnContext.getApnType()
                 + ", reason:" + apnContext.getReason());
+        }
         apnContext.setState(State.CONNECTED);
         // setState(State.CONNECTED);
         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
@@ -1091,21 +1146,25 @@
             if (mPdpResetCount < maxPdpReset) {
                 mPdpResetCount++;
                 EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, mSentSinceLastRecv);
+                if (DBG) log("doRecovery() cleanup all connections mPdpResetCount < max");
                 cleanUpAllConnections(true, Phone.REASON_PDP_RESET);
             } else {
                 mPdpResetCount = 0;
                 EventLog.writeEvent(EventLogTags.PDP_REREGISTER_NETWORK, mSentSinceLastRecv);
+                if (DBG) log("doRecovery() re-register getting preferred network type");
                 mPhone.getServiceStateTracker().reRegisterNetwork(null);
             }
             // TODO: Add increasingly drastic recovery steps, eg,
             // reset the radio, reset the device.
+        } else {
+            if (DBG) log("doRecovery(): ignore, we're not connected");
         }
     }
 
     @Override
     protected void startNetStatPoll() {
         if (getOverallState() == State.CONNECTED && mNetStatPollEnabled == false) {
-            log("[DataConnection] Start poll NetStat");
+            if (DBG) log("startNetStatPoll");
             resetPollStats();
             mNetStatPollEnabled = true;
             mPollNetStat.run();
@@ -1116,12 +1175,12 @@
     protected void stopNetStatPoll() {
         mNetStatPollEnabled = false;
         removeCallbacks(mPollNetStat);
-        log("[DataConnection] Stop poll NetStat");
+        if (DBG) log("stopNetStatPoll");
     }
 
     @Override
     protected void restartRadio() {
-        log("************TURN OFF RADIO**************");
+        if (DBG) log("restartRadio: ************TURN OFF RADIO**************");
         cleanUpAllConnections(true, Phone.REASON_RADIO_TURNED_OFF);
         mPhone.getServiceStateTracker().powerOffRadioSafely(this);
         /* Note: no need to call setRadioPower(true).  Assuming the desired
@@ -1202,7 +1261,7 @@
                 if (mNoRecvPollCount < noRecvPollLimit) {
                     // It's possible the PDP context went down and we weren't notified.
                     // Start polling the context list in an attempt to recover.
-                    if (DBG) log("no DATAIN in a while; polling PDP");
+                    if (DBG) log("Polling: no DATAIN in a while; polling PDP");
                     mPhone.mCM.getDataCallList(obtainMessage(EVENT_DATA_STATE_CHANGED));
 
                     mNoRecvPollCount++;
@@ -1212,7 +1271,7 @@
                             Settings.Secure.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS,
                             POLL_NETSTAT_SLOW_MILLIS);
                 } else {
-                    if (DBG) log("Sent " + String.valueOf(mSentSinceLastRecv) +
+                    if (DBG) log("Polling: Sent " + String.valueOf(mSentSinceLastRecv) +
                                         " pkts since last received start recovery process");
                     stopNetStatPoll();
                     sendMessage(obtainMessage(EVENT_START_RECOVERY));
@@ -1262,14 +1321,12 @@
 
     private void reconnectAfterFail(FailCause lastFailCauseCode, ApnContext apnContext) {
         if (apnContext == null) {
-            Log.d(LOG_TAG, "It is impossible");
+            loge("reconnectAfterFail: apnContext == null, impossible");
             return;
         }
         if (apnContext.getState() == State.FAILED) {
             if (!apnContext.getDataConnection().isRetryNeeded()) {
-                if (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)){
-                    // if no more retries on a secondary APN attempt, tell the world and revert.
-                    apnContext.setDataConnection(null);
+                if (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)) {
                     notifyDataConnection(Phone.REASON_APN_FAILED);
                     return;
                 }
@@ -1278,7 +1335,7 @@
                     apnContext.getDataConnection().retryForeverUsingLastTimeout();
                 } else {
                     // Try to Re-register to the network.
-                    log("PDP activate failed, Reregistering to the network");
+                    if (DBG) log("reconnectAfterFail: activate failed, Reregistering to network");
                     mReregisterOnReconnectFailure = true;
                     mPhone.getServiceStateTracker().reRegisterNetwork(null);
                     apnContext.getDataConnection().resetRetryCount();
@@ -1287,8 +1344,10 @@
             }
 
             int nextReconnectDelay = apnContext.getDataConnection().getRetryTimer();
-            log("PDP activate failed. Scheduling next attempt for "
+            if (DBG) {
+                log("reconnectAfterFail: activate failed. Scheduling next attempt for "
                     + (nextReconnectDelay / 1000) + "s");
+            }
 
             AlarmManager am =
                 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
@@ -1305,8 +1364,10 @@
             apnContext.getDataConnection().increaseRetryCount();
 
             if (!shouldPostNotification(lastFailCauseCode)) {
-                Log.d(LOG_TAG, "NOT Posting GPRS Unavailable notification "
+                if (DBG) {
+                    log("reconnectAfterFail: NOT Posting GPRS Unavailable notification "
                                 + "-- likely transient error");
+                }
             } else {
                 notifyNoData(lastFailCauseCode, apnContext);
             }
@@ -1315,7 +1376,7 @@
 
     private void notifyNoData(GsmDataConnection.FailCause lastFailCauseCode,
                               ApnContext apnContext) {
-        if (DBG) log( "notifyNoData for type:" + apnContext.getApnType());
+        if (DBG) log( "notifyNoData: type=" + apnContext.getApnType());
         apnContext.setState(State.FAILED);
         if (lastFailCauseCode.isPermanentFail()
             && (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT))) {
@@ -1327,7 +1388,7 @@
         if (DBG) log("onRecordsLoaded: createAllApnList");
         createAllApnList();
         if (mRadioAvailable) {
-            if (DBG) log("onRecordsLoaded, notifying data availability");
+            if (DBG) log("onRecordsLoaded: notifying data availability");
             notifyDataAvailability(null);
         }
         setupDataOnReadyApns(Phone.REASON_SIM_LOADED);
@@ -1337,7 +1398,8 @@
     protected void onSetDependencyMet(String apnType, boolean met) {
         ApnContext apnContext = mApnContexts.get(apnType);
         if (apnContext == null) {
-            log("ApnContext not found in onSetDependencyMet(" + apnType + ", " + met + ")");
+            loge("onSetDependencyMet: ApnContext not found in onSetDependencyMet(" +
+                    apnType + ", " + met + ")");
             return;
         }
         applyNewState(apnContext, apnContext.isEnabled(), met);
@@ -1373,12 +1435,15 @@
                     }
                     trySetup = true;
                 } else {
-                    // TODO send notifications
-                    if (DBG) {
-                        log("Found existing connection for " + apnContext.getApnType() +
-                                ": " + conn);
-                    }
+                    int refCount = conn.incAndGetRefCount();
                     apnContext.setDataConnection(conn);
+                    apnContext.setDataConnectionAc(
+                            mDataConnectionAsyncChannels.get(conn.getDataConnectionId()));
+                    if (DBG) {
+                        log("applyNewState: Found existing connection for " +
+                                apnContext.getApnType() + " inc refCount=" + refCount +
+                                " conn=" + conn);
+                    }
                 }
             }
         }
@@ -1395,9 +1460,16 @@
             DataConnection conn = c.getDataConnection();
             if (conn != null) {
                 ApnSetting apnSetting = c.getApnSetting();
-                if (apnSetting != null && apnSetting.canHandleType(apnType)) return conn;
+                if (apnSetting != null && apnSetting.canHandleType(apnType)) {
+                    if (DBG) {
+                        log("checkForConnectionForApnContext: apnContext=" + apnContext +
+                                " found conn=" + conn);
+                    }
+                    return conn;
+                }
             }
         }
+        if (DBG) log("checkForConnectionForApnContext: apnContext=" + apnContext + " NO conn");
         return null;
     }
 
@@ -1405,43 +1477,47 @@
     protected void onEnableApn(int apnId, int enabled) {
         ApnContext apnContext = mApnContexts.get(apnIdToType(apnId));
         if (apnContext == null) {
-            log("ApnContext not found in onEnableApn(" + apnId + ", " + enabled + ")");
+            loge("onEnableApn(" + apnId + ", " + enabled + "): NO ApnContext");
             return;
         }
         // TODO change our retry manager to use the appropriate numbers for the new APN
-        log("onEnableApn with ApnContext E");
+        if (DBG) log("onEnableApn: apnContext=" + apnContext + " call applyNewState");
         applyNewState(apnContext, enabled == ENABLED, apnContext.getDependencyMet());
     }
 
     @Override
     // TODO: We shouldnt need this.
     protected boolean onTrySetupData(String reason) {
+        if (DBG) log("onTrySetupData: reason=" + reason);
         setupDataOnReadyApns(reason);
         return true;
     }
 
     protected boolean onTrySetupData(ApnContext apnContext) {
+        if (DBG) log("onTrySetupData: apnContext=" + apnContext);
         return trySetupData(apnContext);
     }
 
     @Override
     protected void onRoamingOff() {
+        if (DBG) log("onRoamingOff");
         setupDataOnReadyApns(Phone.REASON_ROAMING_OFF);
     }
 
     @Override
     protected void onRoamingOn() {
         if (getDataOnRoamingEnabled()) {
+            if (DBG) log("onRoamingOn: setup data on roaming");
             setupDataOnReadyApns(Phone.REASON_ROAMING_ON);
         } else {
-            if (DBG) log("Tear down data connection on roaming.");
+            if (DBG) log("onRoamingOn: Tear down data connection on roaming.");
             cleanUpAllConnections(true, Phone.REASON_ROAMING_ON);
         }
     }
 
     @Override
     protected void onRadioAvailable() {
-
+        if (DBG) log("onRadioAvailable");
         mRadioAvailable = true;
         if (mPhone.getSimulatedRadioControl() != null) {
             // Assume data is connected on the simulator
@@ -1449,7 +1525,7 @@
             // setState(State.CONNECTED);
             notifyDataConnection(null);
 
-            log("We're on the simulator; assuming data is connected");
+            log("onRadioAvailable: We're on the simulator; assuming data is connected");
         }
 
         if (mPhone.mSIMRecords.getRecordsLoaded()) {
@@ -1477,7 +1553,7 @@
             // FIXME  this can be improved
             log("We're on the simulator; assuming radio off is meaningless");
         } else {
-            if (DBG) log("Radio is off and clean up all connection");
+            if (DBG) log("onRadioOffOrNotAvailable: is off and clean up all connections");
             cleanUpAllConnections(false, Phone.REASON_RADIO_TURNED_OFF);
         }
         notifyDataAvailability(null);
@@ -1490,27 +1566,30 @@
 
         if(ar.userObj instanceof ApnContext){
             apnContext = (ApnContext)ar.userObj;
+        } else {
+            throw new RuntimeException("onDataSetupComplete: No apnContext");
         }
 
-        if (ar.exception == null) {
-            // Everything is setup
-            // TODO: We should clear LinkProperties/Capabilities when torn down or disconnected
+        if (isDataSetupCompleteOk(ar)) {
+            DataConnectionAc dcac = apnContext.getDataConnectionAc();
+            if (dcac == null) {
+                throw new RuntimeException("onDataSetupCompete: No dcac");
+            }
+            DataConnection dc = apnContext.getDataConnection();
+
             if (DBG) {
                 log(String.format("onDataSetupComplete: success apn=%s",
-                    apnContext.getWaitingApns().get(0).apn));
+                    apnContext.getWaitingApns().get(0).apn) + " refCount=" + dc.getRefCount());
             }
-            mLinkProperties = getLinkProperties(apnContext.getApnType());
-            mLinkCapabilities = getLinkCapabilities(apnContext.getApnType());
-
             ApnSetting apn = apnContext.getApnSetting();
             if (apn.proxy != null && apn.proxy.length() != 0) {
                 try {
                     ProxyProperties proxy = new ProxyProperties(apn.proxy,
                             Integer.parseInt(apn.port), null);
-                    mLinkProperties.setHttpProxy(proxy);
+                    dcac.setLinkPropertiesHttpProxySync(proxy);
                 } catch (NumberFormatException e) {
-                    loge("NumberFormatException making ProxyProperties (" + apn.port +
-                            "): " + e);
+                    loge("onDataSetupComplete: NumberFormatException making ProxyProperties (" +
+                            apn.port + "): " + e);
                 }
             }
 
@@ -1518,7 +1597,7 @@
             if(TextUtils.equals(apnContext.getApnType(),Phone.APN_TYPE_DEFAULT)) {
                 SystemProperties.set("gsm.defaultpdpcontext.active", "true");
                 if (canSetPreferApn && mPreferredApn == null) {
-                    log("PREFERED APN is null");
+                    if (DBG) log("onDataSetupComplete: PREFERED APN is null");
                     mPreferredApn = apnContext.getApnSetting();
                     if (mPreferredApn != null) {
                         setPreferredApn(mPreferredApn.id);
@@ -1528,19 +1607,12 @@
                 SystemProperties.set("gsm.defaultpdpcontext.active", "false");
             }
             notifyDefaultData(apnContext);
-
-            // TODO: For simultaneous PDP support, we need to build another
-            // trigger another TRY_SETUP_DATA for the next APN type.  (Note
-            // that the existing connection may service that type, in which
-            // case we should try the next type, etc.
-            // I dont believe for simultaneous PDP you need to trigger. Each
-            // Connection should be independent and they can be setup simultaneously
-            // So, dont have to wait till one is finished.
         } else {
-            GsmDataConnection.FailCause cause;
-            cause = (GsmDataConnection.FailCause) (ar.result);
+            String apnString;
+            DataConnection.FailCause cause;
+
+            cause = (DataConnection.FailCause) (ar.result);
             if (DBG) {
-                String apnString;
                 try {
                     apnString = apnContext.getWaitingApns().get(0).apn;
                 } catch (Exception e) {
@@ -1573,7 +1645,6 @@
                         log("onDataSetupComplete: All APN's had permanent failures, stop retrying");
                     }
                     apnContext.setState(State.FAILED);
-                    apnContext.setDataConnection(null);
                     notifyDataConnection(Phone.REASON_APN_FAILED);
                 } else {
                     if (DBG) log("onDataSetupComplete: Not all permanent failures, retry");
@@ -1587,6 +1658,11 @@
                 sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext),
                         APN_DELAY_MILLIS);
             }
+
+            int refCount = releaseApnContext(apnContext, false);
+            if (DBG) {
+                log("onDataSetupComplete: error apn=%s" + apnString + " refCount=" + refCount);
+            }
         }
     }
 
@@ -1597,7 +1673,7 @@
     protected void onDisconnectDone(int connId, AsyncResult ar) {
         ApnContext apnContext = null;
 
-        if(DBG) log("EVENT_DISCONNECT_DONE connId=" + connId);
+        if(DBG) log("onDisconnectDone: EVENT_DISCONNECT_DONE connId=" + connId);
         if (ar.userObj instanceof ApnContext) {
             apnContext = (ApnContext) ar.userObj;
         } else {
@@ -1610,9 +1686,7 @@
 
         // Check if APN disabled.
         if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_APN_DISABLE) {
-           apnContext.setEnabled(false);
            apnContext.setPendingAction(ApnContext.PENDING_ACTION_NONE);
-           apnContext.setDataConnection(null);
         }
         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
 
@@ -1648,7 +1722,9 @@
 
     @Override
     protected void onVoiceCallStarted() {
+        if (DBG) log("onVoiceCallStarted");
         if (isConnected() && ! mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
+            if (DBG) log("onVoiceCallStarted stop polling");
             stopNetStatPoll();
             notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED);
         }
@@ -1656,6 +1732,7 @@
 
     @Override
     protected void onVoiceCallEnded() {
+        if (DBG) log("onVoiceCallEnded");
         if (isConnected()) {
             if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
                 startNetStatPoll();
@@ -1688,10 +1765,10 @@
 
     @Override
     protected void notifyDataConnection(String reason) {
-        if (DBG) log("notify all enabled connection for:" + reason);
+        if (DBG) log("notifyDataConnection: reason=" + reason);
         for (ApnContext apnContext : mApnContexts.values()) {
             if (apnContext.isReady()) {
-                if (DBG) log("notify for type:"+apnContext.getApnType());
+                if (DBG) log("notifyDataConnection: type:"+apnContext.getApnType());
                 mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
                         apnContext.getApnType());
             }
@@ -1738,17 +1815,16 @@
     }
 
     /** Return the id for a new data connection */
-    private GsmDataConnection createDataConnection(ApnContext apnContext) {
-        String apnType = apnContext.getApnType();
-        log("createDataConnection(" + apnType + ") E");
+    private GsmDataConnection createDataConnection(String apnType) {
+        if (DBG) log("createDataConnection(" + apnType + ") E");
         RetryManager rm = new RetryManager();
 
         if (apnType.equals(Phone.APN_TYPE_DEFAULT)) {
             if (!rm.configure(SystemProperties.get("ro.gsm.data_retry_config"))) {
                 if (!rm.configure(DEFAULT_DATA_RETRY_CONFIG)) {
                     // Should never happen, log an error and default to a simple linear sequence.
-                    log("Could not configure using DEFAULT_DATA_RETRY_CONFIG="
-                            + DEFAULT_DATA_RETRY_CONFIG);
+                    loge("createDataConnection: Could not configure using " +
+                            "DEFAULT_DATA_RETRY_CONFIG=" + DEFAULT_DATA_RETRY_CONFIG);
                     rm.configure(20, 2000, 1000);
                 }
             }
@@ -1756,8 +1832,8 @@
             if (!rm.configure(SystemProperties.get("ro.gsm.2nd_data_retry_config"))) {
                 if (!rm.configure(SECONDARY_DATA_RETRY_CONFIG)) {
                     // Should never happen, log an error and default to a simple sequence.
-                    log("Could note configure using SECONDARY_DATA_RETRY_CONFIG="
-                            + SECONDARY_DATA_RETRY_CONFIG);
+                    loge("createDataConnection: Could note configure using " +
+                            "SECONDARY_DATA_RETRY_CONFIG=" + SECONDARY_DATA_RETRY_CONFIG);
                     rm.configure("max_retries=3, 333, 333, 333");
                 }
             }
@@ -1767,18 +1843,25 @@
         GsmDataConnection conn = GsmDataConnection.makeDataConnection(mPhone, id, rm);
         conn.resetRetryCount();
         mDataConnections.put(id, conn);
-        apnContext.setDataConnection(conn);
+        DataConnectionAc dcac = new DataConnectionAc(conn, LOG_TAG);
+        int status = dcac.fullyConnectSync(mPhone.getContext(), this, conn.getHandler());
+        if (status == AsyncChannel.STATUS_SUCCESSFUL) {
+            mDataConnectionAsyncChannels.put(dcac.dataConnection.getDataConnectionId(), dcac);
+        } else {
+            loge("createDataConnection: Could not connect to dcac.mDc=" + dcac.dataConnection +
+                    " status=" + status);
+        }
 
-        log("createDataConnection(" + apnType + ") X id=" + id);
+        if (DBG) log("createDataConnection(" + apnType + ") X id=" + id);
         return conn;
     }
 
     private void destroyDataConnections() {
         if(mDataConnections != null) {
-            log("destroyDataConnectionList clear mDataConnectionList");
+            if (DBG) log("destroyDataConnections: clear mDataConnectionList");
             mDataConnections.clear();
         } else {
-            log("destroyDataConnectionList mDataConnecitonList is empty, ignore");
+            if (DBG) log("destroyDataConnectionList mDataConnecitonList is empty, ignore");
         }
     }
 
@@ -1802,8 +1885,10 @@
         String operator = mPhone.mSIMRecords.getSIMOperatorNumeric();
         if (requestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
             if (canSetPreferApn && mPreferredApn != null) {
-                log("Preferred APN:" + operator + ":"
+                if (DBG) {
+                    log("buildWaitingApns: Preferred APN:" + operator + ":"
                         + mPreferredApn.numeric + ":" + mPreferredApn);
+                }
                 if (mPreferredApn.numeric.equals(operator)) {
                     apnList.add(mPreferredApn);
                     if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList);
@@ -1894,10 +1979,10 @@
 
     @Override
     public void handleMessage (Message msg) {
-        if (DBG) log("GSMDataConnTrack handleMessage "+msg);
+        if (DBG) log("handleMessage msg=" + msg);
 
         if (!mPhone.mIsTheCurrentActivePhone || mIsDisposed) {
-            log("Ignore GSM msgs since GSM phone is inactive");
+            loge("handleMessage: Ignore GSM msgs since GSM phone is inactive");
             return;
         }
 
@@ -1941,7 +2026,7 @@
                  * PDP context and notify us with PDP_CONTEXT_CHANGED.
                  * But we should stop the network polling and prevent reset PDP.
                  */
-                log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted);
+                if (DBG) log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted);
                 stopNetStatPoll();
                 mIsPsRestricted = true;
                 break;
@@ -1951,7 +2036,7 @@
                  * When PS restrict is removed, we need setup PDP connection if
                  * PDP connection is down.
                  */
-                log("EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted);
+                if (DBG) log("EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted);
                 mIsPsRestricted  = false;
                 if (isConnected()) {
                     startNetStatPoll();
@@ -1968,19 +2053,20 @@
             case EVENT_TRY_SETUP_DATA:
                 if (msg.obj instanceof ApnContext) {
                     onTrySetupData((ApnContext)msg.obj);
+                } else if (msg.obj instanceof String) {
+                    onTrySetupData((String)msg.obj);
                 } else {
-                    if (msg.obj instanceof String) {
-                        onTrySetupData((String)msg.obj);
-                    }
+                    loge("EVENT_TRY_SETUP request w/o apnContext or String");
                 }
                 break;
 
             case EVENT_CLEAN_UP_CONNECTION:
                 boolean tearDown = (msg.arg1 == 0) ? false : true;
+                if (DBG) log("EVENT_CLEAN_UP_CONNECTION tearDown=" + tearDown);
                 if (msg.obj instanceof ApnContext) {
                     cleanUpConnection(tearDown, (ApnContext)msg.obj);
                 } else {
-                    loge("[GsmDataConnectionTracker] connectpion cleanup request w/o apn context");
+                    loge("EVENT_CLEAN_UP_CONNECTION request w/o apn context");
                 }
                 break;
             default:
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index c5c3f70..6285880 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -37,6 +37,15 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+
+        <activity
+                android:name="GLTextureViewActivity"
+                android:label="_TextureViewGL">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
         
         <activity
                 android:name="BitmapMeshActivity"
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
new file mode 100644
index 0000000..7f97098
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.app.Activity;
+import android.graphics.SurfaceTexture;
+import android.opengl.GLES20;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.TextureView;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGL11;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+import javax.microedition.khronos.opengles.GL;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class GLTextureViewActivity extends Activity implements TextureView.SurfaceTextureListener {
+    private RenderThread mRenderThread;
+    private TextureView mTextureView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mTextureView = new TextureView(this);
+        mTextureView.setSurfaceTextureListener(this);
+
+        setContentView(mTextureView, new FrameLayout.LayoutParams(500, 400, Gravity.CENTER));
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mRenderThread.finish();
+    }
+
+    @Override
+    public void onSurfaceTextureAvailable(SurfaceTexture surface) {
+        mRenderThread = new RenderThread(surface);
+        mRenderThread.start();
+
+        mTextureView.setCameraDistance(5000);
+
+        ObjectAnimator animator = ObjectAnimator.ofFloat(mTextureView, "rotationY", 0.0f, 360.0f);
+        animator.setRepeatMode(ObjectAnimator.REVERSE);
+        animator.setRepeatCount(ObjectAnimator.INFINITE);
+        animator.setDuration(4000);
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                ((View) mTextureView.getParent()).invalidate();
+            }
+        });
+        animator.start();
+    }
+
+    @Override
+    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+    }
+
+    private static class RenderThread extends Thread {
+        private static final String LOG_TAG = "GLTextureView";
+
+        static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+        static final int EGL_SURFACE_TYPE = 0x3033;
+        static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
+        static final int EGL_OPENGL_ES2_BIT = 4;
+
+        private volatile boolean mFinished;
+
+        private SurfaceTexture mSurface;
+        
+        private EGL10 mEgl;
+        private EGLDisplay mEglDisplay;
+        private EGLConfig mEglConfig;
+        private EGLContext mEglContext;
+        private EGLSurface mEglSurface;
+        private GL mGL;
+
+        RenderThread(SurfaceTexture surface) {
+            mSurface = surface;
+        }
+
+        @Override
+        public void run() {
+            initGL();
+
+            float red = 0.0f;
+            while (!mFinished) {
+                checkCurrent();
+
+                GLES20.glClearColor(red, 0.0f, 0.0f, 1.0f);
+                int error = GLES20.glGetError();
+                if (error != GLES20.GL_NO_ERROR) {
+                    Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error));
+                }
+
+                GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+                error = GLES20.glGetError();
+                if (error != GLES20.GL_NO_ERROR) {
+                    Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error));
+                }
+
+                if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
+                    throw new RuntimeException("Cannot swap buffers");
+                }
+                
+                try {
+                    Thread.sleep(20);
+                } catch (InterruptedException e) {
+                    // Ignore
+                }
+
+                red += 0.021f;
+                if (red > 1.0f) red = 0.0f;
+            }
+
+            finishGL();
+        }
+
+        private void finishGL() {
+            mEgl.eglDestroyContext(mEglDisplay, mEglContext);
+            mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+        }
+
+        private void checkCurrent() {
+            if (!mEglContext.equals(mEgl.eglGetCurrentContext()) ||
+                    !mEglSurface.equals(mEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) {
+                if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+                    throw new RuntimeException("eglMakeCurrent failed "
+                            + getEGLErrorString(mEgl.eglGetError()));
+                }
+            }
+        }
+        
+        private void initGL() {
+            mEgl = (EGL10) EGLContext.getEGL();
+
+            mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+            if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
+                throw new RuntimeException("eglGetDisplay failed "
+                        + getEGLErrorString(mEgl.eglGetError()));
+            }
+            
+            int[] version = new int[2];
+            if (!mEgl.eglInitialize(mEglDisplay, version)) {
+                throw new RuntimeException("eglInitialize failed " +
+                        getEGLErrorString(mEgl.eglGetError()));
+            }
+
+            mEglConfig = chooseEglConfig();
+            if (mEglConfig == null) {
+                throw new RuntimeException("eglConfig not initialized");
+            }
+            
+            mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
+
+            mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface, null);
+
+            if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
+                int error = mEgl.eglGetError();
+                if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
+                    Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
+                    return;
+                }
+                throw new RuntimeException("createWindowSurface failed "
+                        + getEGLErrorString(error));
+            }
+
+            if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+                throw new RuntimeException("eglMakeCurrent failed "
+                        + getEGLErrorString(mEgl.eglGetError()));
+            }
+
+            mGL = mEglContext.getGL();
+        }
+        
+
+        EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
+            int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
+            return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);            
+        }
+
+        private EGLConfig chooseEglConfig() {
+            int[] configsCount = new int[1];
+            EGLConfig[] configs = new EGLConfig[1];
+            int[] configSpec = getConfig();
+            if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
+                throw new IllegalArgumentException("eglChooseConfig failed " +
+                        getEGLErrorString(mEgl.eglGetError()));
+            } else if (configsCount[0] > 0) {
+                return configs[0];
+            }
+            return null;
+        }
+        
+        private int[] getConfig() {
+            return new int[] {
+                    EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+                    EGL10.EGL_RED_SIZE, 8,
+                    EGL10.EGL_GREEN_SIZE, 8,
+                    EGL10.EGL_BLUE_SIZE, 8,
+                    EGL10.EGL_ALPHA_SIZE, 8,
+                    EGL10.EGL_DEPTH_SIZE, 0,
+                    EGL10.EGL_STENCIL_SIZE, 0,
+                    EGL10.EGL_NONE
+            };
+        }
+
+        static String getEGLErrorString(int error) {
+            switch (error) {
+                case EGL10.EGL_SUCCESS:
+                    return "EGL_SUCCESS";
+                case EGL10.EGL_NOT_INITIALIZED:
+                    return "EGL_NOT_INITIALIZED";
+                case EGL10.EGL_BAD_ACCESS:
+                    return "EGL_BAD_ACCESS";
+                case EGL10.EGL_BAD_ALLOC:
+                    return "EGL_BAD_ALLOC";
+                case EGL10.EGL_BAD_ATTRIBUTE:
+                    return "EGL_BAD_ATTRIBUTE";
+                case EGL10.EGL_BAD_CONFIG:
+                    return "EGL_BAD_CONFIG";
+                case EGL10.EGL_BAD_CONTEXT:
+                    return "EGL_BAD_CONTEXT";
+                case EGL10.EGL_BAD_CURRENT_SURFACE:
+                    return "EGL_BAD_CURRENT_SURFACE";
+                case EGL10.EGL_BAD_DISPLAY:
+                    return "EGL_BAD_DISPLAY";
+                case EGL10.EGL_BAD_MATCH:
+                    return "EGL_BAD_MATCH";
+                case EGL10.EGL_BAD_NATIVE_PIXMAP:
+                    return "EGL_BAD_NATIVE_PIXMAP";
+                case EGL10.EGL_BAD_NATIVE_WINDOW:
+                    return "EGL_BAD_NATIVE_WINDOW";
+                case EGL10.EGL_BAD_PARAMETER:
+                    return "EGL_BAD_PARAMETER";
+                case EGL10.EGL_BAD_SURFACE:
+                    return "EGL_BAD_SURFACE";
+                case EGL11.EGL_CONTEXT_LOST:
+                    return "EGL_CONTEXT_LOST";
+                default:
+                    return "0x" + Integer.toHexString(error);
+            }
+        }
+
+        void finish() {
+            mFinished = true;
+        }
+    }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java
index 55fab3f..7173a85 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java
@@ -86,6 +86,14 @@
             canvas.drawLines(copyPoints, 0, 12, p);
         }
 
+        private void drawVerticalLine(Canvas canvas, Paint p, float length, float x, float y) {
+            canvas.drawLine(x, y, x, y + length, p);
+        }
+
+        private void drawDiagonalLine(Canvas canvas, Paint p, float length, float x, float y) {
+            canvas.drawLine(x, y, x + length, y + length, p);
+        }
+
         @Override
         protected void onDraw(Canvas canvas) {
             super.onDraw(canvas);
@@ -145,6 +153,99 @@
             canvas.translate(60, 0);
             drawLines(canvas, p, mOffset/2, yOffset/2);
             canvas.restore();
+
+            yOffset += 100;
+            canvas.save();
+            p.setStrokeWidth(1);
+            float x = 10 + mOffset;
+            for (float length = 1; length <= 10; length +=1 ) {
+                p.setAntiAlias(false);
+                drawVerticalLine(canvas, p, length, x, yOffset);
+                x += 5;
+                p.setAntiAlias(true);
+                drawVerticalLine(canvas, p, length, x, yOffset);
+                x += 5;
+            }
+            p.setStrokeWidth(5);
+            for (float length = 1; length <= 10; length +=1 ) {
+                p.setAntiAlias(false);
+                drawVerticalLine(canvas, p, length, x, yOffset);
+                x += 10;
+                p.setAntiAlias(true);
+                drawVerticalLine(canvas, p, length, x, yOffset);
+                x += 10;
+            }
+            canvas.restore();
+
+            yOffset += 20;
+            canvas.save();
+            p.setStrokeWidth(1);
+            x = 10 + mOffset;
+            for (float length = 1; length <= 10; length +=1 ) {
+                p.setAntiAlias(false);
+                drawDiagonalLine(canvas, p, length, x, yOffset);
+                x += 5;
+                p.setAntiAlias(true);
+                drawDiagonalLine(canvas, p, length, x, yOffset);
+                x += 5;
+            }
+            p.setStrokeWidth(2);
+            for (float length = 1; length <= 10; length +=1 ) {
+                p.setAntiAlias(false);
+                drawDiagonalLine(canvas, p, length, x, yOffset);
+                x += 10;
+                p.setAntiAlias(true);
+                drawDiagonalLine(canvas, p, length, x, yOffset);
+                x += 10;
+            }
+            canvas.restore();
+
+            yOffset += 20;
+            canvas.save();
+            p.setStrokeWidth(1);
+            x = 10 + mOffset;
+            for (float length = 1; length <= 10; length +=1 ) {
+                p.setAntiAlias(false);
+                canvas.drawLine(x, yOffset, x + 1, yOffset + length, p);
+                x += 5;
+                p.setAntiAlias(true);
+                canvas.drawLine(x, yOffset, x + 1, yOffset + length, p);
+                x += 5;
+            }
+            p.setStrokeWidth(2);
+            for (float length = 1; length <= 10; length +=1 ) {
+                p.setAntiAlias(false);
+                canvas.drawLine(x, yOffset, x + 1, yOffset + length, p);
+                x += 10;
+                p.setAntiAlias(true);
+                canvas.drawLine(x, yOffset, x + 1, yOffset + length, p);
+                x += 10;
+            }
+            canvas.restore();
+
+            yOffset += 20;
+            canvas.save();
+            p.setStrokeWidth(1);
+            x = 10 + mOffset;
+            for (float length = 1; length <= 10; length +=1 ) {
+                p.setAntiAlias(false);
+                canvas.drawLine(x, yOffset, x + length, yOffset + 1, p);
+                x += 5;
+                p.setAntiAlias(true);
+                canvas.drawLine(x, yOffset, x + length, yOffset + 1, p);
+                x += 5;
+            }
+            p.setStrokeWidth(2);
+            for (float length = 1; length <= 10; length +=1 ) {
+                p.setAntiAlias(false);
+                canvas.drawLine(x, yOffset, x + length, yOffset + 1, p);
+                x += 10;
+                p.setAntiAlias(true);
+                canvas.drawLine(x, yOffset, x + length, yOffset + 1, p);
+                x += 10;
+            }
+            canvas.restore();
+
         }
     }
 }
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
index 4726672..2feda57 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
@@ -84,4 +84,9 @@
         animator.setDuration(4000);
         animator.start();
     }
+
+    @Override
+    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+        // Ignored, the Camera does all the work for us
+    }
 }
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.rs
index f2f9a36..16ebe08 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.rs
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.rs
@@ -63,7 +63,7 @@
 
 static void copyInput() {
     rs_allocation ain;
-    rsSetObject(&ain,rsGetAllocation(InPixel));
+    ain = rsGetAllocation(InPixel);
     uint32_t dimx = rsAllocationGetDimX(ain);
     uint32_t dimy = rsAllocationGetDimY(ain);
     for (uint32_t y = 0; y < dimy; y++) {
diff --git a/tests/RenderScriptTests/PerfTest/AndroidManifest.xml b/tests/RenderScriptTests/PerfTest/AndroidManifest.xml
index e024882..aafd176 100644
--- a/tests/RenderScriptTests/PerfTest/AndroidManifest.xml
+++ b/tests/RenderScriptTests/PerfTest/AndroidManifest.xml
@@ -1,6 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.perftest">
+    
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    
     <uses-sdk android:minSdkVersion="11" />
     <application android:label="PerfTest"
       android:icon="@drawable/test_pattern">
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
index 4d4adf6..7cd55fa 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
@@ -17,7 +17,14 @@
 package com.android.perftest;
 
 import java.io.Writer;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
 
+import android.os.Environment;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -36,9 +43,15 @@
 
 public class RsBenchRS {
 
+    private static final String TAG = "RsBenchRS";
+
     int mWidth;
     int mHeight;
     int mLoops;
+    int mCurrentLoop;
+
+    int mBenchmarkDimX;
+    int mBenchmarkDimY;
 
     public RsBenchRS() {
     }
@@ -53,6 +66,9 @@
         mMode = 0;
         mMaxModes = 0;
         mLoops = loops;
+        mCurrentLoop = 0;
+        mBenchmarkDimX = 1280;
+        mBenchmarkDimY = 720;
         initRS();
     }
 
@@ -120,25 +136,66 @@
     int mMode;
     int mMaxModes;
 
+    String[] mTestNames;
+    float[] mLocalTestResults;
+
     public void onActionDown(int x, int y) {
         mMode ++;
         mMode = mMode % mMaxModes;
         mScript.set_gDisplayMode(mMode);
     }
 
+    private void saveTestResults() {
+        String state = Environment.getExternalStorageState();
+        if (!Environment.MEDIA_MOUNTED.equals(state)) {
+            Log.v(TAG, "sdcard is read only");
+            return;
+        }
+        File sdCard = Environment.getExternalStorageDirectory();
+        if (!sdCard.canWrite()) {
+            Log.v(TAG, "ssdcard is read only");
+            return;
+        }
+
+        File resultFile = new File(sdCard, "rsbench_result" + mCurrentLoop + ".csv");
+        resultFile.setWritable(true, false);
+
+        try {
+            BufferedWriter results = new BufferedWriter(new FileWriter(resultFile));
+            for (int i = 0; i < mLocalTestResults.length; i ++) {
+                results.write(mTestNames[i] + ", " + mLocalTestResults[i] + ",\n");
+            }
+            results.close();
+            Log.v(TAG, "Saved results in: " + resultFile.getAbsolutePath());
+        } catch (IOException e) {
+            Log.v(TAG, "Unable to write result file " + e.getMessage());
+        }
+    }
+
     /**
      * Create a message handler to handle message sent from the script
      */
     protected RSMessageHandler mRsMessage = new RSMessageHandler() {
         public void run() {
-            if (mID == mScript.get_RS_MSG_TEST_DONE()) {
+            if (mID == mScript.get_RS_MSG_RESULTS_READY()) {
+                for (int i = 0; i < mLocalTestResults.length; i ++) {
+                    mLocalTestResults[i] = Float.intBitsToFloat(mData[i]);
+                }
+                saveTestResults();
+                if (mLoops > 0) {
+                    mCurrentLoop ++;
+                    mCurrentLoop = mCurrentLoop % mLoops;
+                }
+                return;
+
+            } else if (mID == mScript.get_RS_MSG_TEST_DONE()) {
                 synchronized(this) {
                     stopTest = true;
                     this.notifyAll();
                 }
                 return;
             } else {
-                Log.v("RsBenchRS", "Perf test got unexpected message");
+                Log.v(TAG, "Perf test got unexpected message");
                 return;
             }
         }
@@ -247,7 +304,7 @@
         mPVA = new ProgramVertexFixedFunction.Constants(mRS);
         ((ProgramVertexFixedFunction)mProgVertex).bindConstants(mPVA);
         Matrix4f proj = new Matrix4f();
-        proj.loadOrthoWindow(mWidth, mHeight);
+        proj.loadOrthoWindow(mBenchmarkDimX, mBenchmarkDimY);
         mPVA.setProjection(proj);
 
         mScript.set_gProgVertex(mProgVertex);
@@ -370,11 +427,11 @@
     }
 
     private void initMesh() {
-        m10by10Mesh = getMbyNMesh(mWidth, mHeight, 10, 10);
+        m10by10Mesh = getMbyNMesh(mBenchmarkDimX, mBenchmarkDimY, 10, 10);
         mScript.set_g10by10Mesh(m10by10Mesh);
-        m100by100Mesh = getMbyNMesh(mWidth, mHeight, 100, 100);
+        m100by100Mesh = getMbyNMesh(mBenchmarkDimX, mBenchmarkDimY, 100, 100);
         mScript.set_g100by100Mesh(m100by100Mesh);
-        mWbyHMesh= getMbyNMesh(mWidth, mHeight, mWidth/4, mHeight/4);
+        mWbyHMesh= getMbyNMesh(mBenchmarkDimX, mBenchmarkDimY, mBenchmarkDimX/4, mBenchmarkDimY/4);
         mScript.set_gWbyHMesh(mWbyHMesh);
 
         FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.torus);
@@ -427,6 +484,29 @@
         mScript.set_gCullNone(mCullNone);
     }
 
+    private int strlen(byte[] array) {
+        int count = 0;
+        while(count < array.length && array[count] != 0) {
+            count ++;
+        }
+        return count;
+    }
+
+    private void prepareTestData() {
+        mTestNames = new String[mMaxModes];
+        mLocalTestResults = new float[mMaxModes];
+        int scratchSize = 1024;
+        Allocation scratch = Allocation.createSized(mRS, Element.U8(mRS), scratchSize);
+        byte[] tmp = new byte[scratchSize];
+        mScript.bind_gStringBuffer(scratch);
+        for (int i = 0; i < mMaxModes; i ++) {
+            mScript.invoke_getTestName(i);
+            scratch.copyTo(tmp);
+            int len = strlen(tmp);
+            mTestNames[i] = new String(tmp, 0, len);
+        }
+    }
+
     private void initRS() {
 
         mScript = new ScriptC_rsbench(mRS, mRes, R.raw.rsbench);
@@ -435,6 +515,8 @@
         mMaxModes = mScript.get_gMaxModes();
         mScript.set_gMaxLoops(mLoops);
 
+        prepareTestData();
+
         initSamplers();
         initProgramStore();
         initProgramFragment();
@@ -446,7 +528,7 @@
         initCustomShaders();
 
         Type.Builder b = new Type.Builder(mRS, Element.RGBA_8888(mRS));
-        b.setX(1280).setY(720);
+        b.setX(mBenchmarkDimX).setY(mBenchmarkDimY);
         Allocation offscreen = Allocation.createTyped(mRS,
                                                       b.create(),
                                                       Allocation.USAGE_GRAPHICS_TEXTURE |
@@ -456,7 +538,7 @@
         b = new Type.Builder(mRS,
                              Element.createPixel(mRS, DataType.UNSIGNED_16,
                              DataKind.PIXEL_DEPTH));
-        b.setX(1280).setY(720);
+        b.setX(mBenchmarkDimX).setY(mBenchmarkDimY);
         offscreen = Allocation.createTyped(mRS,
                                            b.create(),
                                            Allocation.USAGE_GRAPHICS_RENDER_TARGET);
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
index 3fc59fc..198e3f8 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
@@ -21,10 +21,16 @@
 
 /* Message sent from script to renderscript */
 const int RS_MSG_TEST_DONE = 100;
+const int RS_MSG_RESULTS_READY = 101;
 
-const int gMaxModes = 26;
+const int gMaxModes = 25;
 int gMaxLoops;
 
+// Allocation to send test names back to java
+char *gStringBuffer = 0;
+// Allocation to write the results into
+static float gResultBuffer[gMaxModes];
+
 rs_program_vertex gProgVertex;
 rs_program_fragment gProgFragmentColor;
 rs_program_fragment gProgFragmentTexture;
@@ -109,11 +115,11 @@
 static void displayFontSamples(int fillNum) {
 
     rs_font fonts[5];
-    rsSetObject(&fonts[0], gFontSans);
-    rsSetObject(&fonts[1], gFontSerif);
-    rsSetObject(&fonts[2], gFontSerifBold);
-    rsSetObject(&fonts[3], gFontSerifBoldItalic);
-    rsSetObject(&fonts[4], gFontSans);
+    fonts[0] = gFontSans;
+    fonts[1] = gFontSerif;
+    fonts[2] = gFontSerifBold;
+    fonts[3] = gFontSerifBoldItalic;
+    fonts[4] = gFontSans;
 
     uint width = gRenderSurfaceW;
     uint height = gRenderSurfaceH;
@@ -140,10 +146,6 @@
             }
         }
     }
-
-    for (int i = 0; i < 5; i ++) {
-        rsClearObject(&fonts[i]);
-    }
 }
 
 static void bindProgramVertexOrtho() {
@@ -172,7 +174,7 @@
     rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
 
     for (int i = 0; i < quadCount; i ++) {
-        float startX = 10 * i, startY = 10 * i;
+        float startX = 5 * i, startY = 5 * i;
         float width = gRenderSurfaceW - startX, height = gRenderSurfaceH - startY;
         rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
                              startX, startY + height, 0, 0, 1,
@@ -642,116 +644,121 @@
 static bool sendMsgFlag = false;
 
 static const char *testNames[] = {
-    "Finished text fill 1,",
-    "Finished text fill 2,",
-    "Finished text fill 3,",
-    "Finished text fill 4,",
-    "Finished text fill 5,",
-    "Finished 25.6k geo flat color,",
-    "Finished 51.2k geo flat color,",
-    "Finished 204.8k geo raster load flat color,",
-    "Finished 25.6k geo texture,",
-    "Finished 51.2k geo texture,",
-    "Finished 204.8k geo raster load texture,",
-    "Finished full screen mesh 10 by 10,",
-    "Finished full screen mesh 100 by 100,",
-    "Finished full screen mesh W / 4 by H / 4,",
-    "Finished 25.6k geo heavy vertex,",
-    "Finished 51.2k geo heavy vertex,",
-    "Finished 204.8k geo raster load heavy vertex,",
-    "Finished singletexture 5x fill,",
-    "Finished 3tex multitexture 5x fill,",
-    "Finished blend singletexture 5x fill,",
-    "Finished blend 3tex multitexture 5x fill,",
-    "Finished 25.6k geo heavy fragment,",
-    "Finished 51.2k geo heavy fragment,",
-    "Finished 204.8k geo raster load heavy fragment,",
-    "Finished 25.6k geo heavy fragment heavy vertex,",
-    "Finished 51.2k geo heavy fragment heavy vertex,",
-    "Finished 204.8k geo raster load heavy fragment heavy vertex,",
+    "Fill screen with text 1 time",
+    "Fill screen with text 3 times",
+    "Fill screen with text 5 times",
+    "Geo test 25.6k flat color",
+    "Geo test 51.2k flat color",
+    "Geo test 204.8k small tries flat color",
+    "Geo test 25.6k single texture",
+    "Geo test 51.2k single texture",
+    "Geo test 204.8k small tries single texture",
+    "Full screen mesh 10 by 10",
+    "Full screen mesh 100 by 100",
+    "Full screen mesh W / 4 by H / 4",
+    "Geo test 25.6k geo heavy vertex",
+    "Geo test 51.2k geo heavy vertex",
+    "Geo test 204.8k geo raster load heavy vertex",
+    "Fill screen 10x singletexture",
+    "Fill screen 10x 3tex multitexture",
+    "Fill screen 10x blended singletexture",
+    "Fill screen 10x blended 3tex multitexture",
+    "Geo test 25.6k heavy fragment",
+    "Geo test 51.2k heavy fragment",
+    "Geo test 204.8k small tries heavy fragment",
+    "Geo test 25.6k heavy fragment heavy vertex",
+    "Geo test 51.2k heavy fragment heavy vertex",
+    "Geo test 204.8k small tries heavy fragment heavy vertex",
 };
 
+void getTestName(int testIndex) {
+    int bufferLen = rsAllocationGetDimX(rsGetAllocation(gStringBuffer));
+    if (testIndex >= gMaxModes) {
+        return;
+    }
+    uint charIndex = 0;
+    while (testNames[testIndex][charIndex] != '\0' && charIndex < bufferLen) {
+        gStringBuffer[charIndex] = testNames[testIndex][charIndex];
+        charIndex ++;
+    }
+    gStringBuffer[charIndex] = '\0';
+}
+
 static void runTest(int index) {
     switch (index) {
     case 0:
         displayFontSamples(1);
         break;
     case 1:
-        displayFontSamples(2);
-        break;
-    case 2:
         displayFontSamples(3);
         break;
-    case 3:
-        displayFontSamples(4);
-        break;
-    case 4:
+    case 2:
         displayFontSamples(5);
         break;
-    case 5:
+    case 3:
         displaySimpleGeoSamples(false, 1);
         break;
-    case 6:
+    case 4:
         displaySimpleGeoSamples(false, 2);
         break;
-    case 7:
+    case 5:
         displaySimpleGeoSamples(false, 8);
         break;
-    case 8:
+    case 6:
         displaySimpleGeoSamples(true, 1);
         break;
-    case 9:
+    case 7:
         displaySimpleGeoSamples(true, 2);
         break;
-    case 10:
+    case 8:
         displaySimpleGeoSamples(true, 8);
         break;
-    case 11:
+    case 9:
         displayMeshSamples(0);
         break;
-    case 12:
+    case 10:
         displayMeshSamples(1);
         break;
-    case 13:
+    case 11:
         displayMeshSamples(2);
         break;
-    case 14:
+    case 12:
         displayCustomShaderSamples(1);
         break;
-    case 15:
+    case 13:
         displayCustomShaderSamples(2);
         break;
+    case 14:
+        displayCustomShaderSamples(10);
+        break;
+    case 15:
+        displaySingletexFill(false, 10);
+        break;
     case 16:
-        displayCustomShaderSamples(8);
+        displayMultitextureSample(false, 10);
         break;
     case 17:
-        displaySingletexFill(false, 5);
+        displaySingletexFill(true, 10);
         break;
     case 18:
-        displayMultitextureSample(false, 5);
+        displayMultitextureSample(true, 8);
         break;
     case 19:
-        displaySingletexFill(true, 5);
-        break;
-    case 20:
-        displayMultitextureSample(true, 5);
-        break;
-    case 21:
         displayPixelLightSamples(1, false);
         break;
-    case 22:
+    case 20:
         displayPixelLightSamples(2, false);
         break;
-    case 23:
+    case 21:
         displayPixelLightSamples(8, false);
         break;
-    case 24:
+    case 22:
         displayPixelLightSamples(1, true);
         break;
-    case 25:
+    case 23:
         displayPixelLightSamples(2, true);
         break;
-    case 26:
+    case 24:
         displayPixelLightSamples(8, true);
         break;
     }
@@ -786,9 +793,10 @@
         return 1;
     }
 
+    gDt = 1.0f / 60.0f;
+
     rsgFinish();
     int64_t start = rsUptimeMillis();
-    rsGetDt();
 
     int drawPos = 0;
     int frameCount = 100;
@@ -805,7 +813,6 @@
         gRenderSurfaceH = rsgGetHeight();
         int size = 8;
         drawOffscreenResult((drawPos+=size)%gRenderSurfaceW, (gRenderSurfaceH * 3) / 4, size, size);
-        gDt = rsGetDt();
     }
 
     rsgFinish();
@@ -813,6 +820,7 @@
     int64_t end = rsUptimeMillis();
     float fps = (float)(frameCount) / ((float)(end - start)*0.001f);
     rsDebug(testNames[benchMode], fps);
+    gResultBuffer[benchMode] = fps;
 
     drawOffscreenResult(0, 0,
                         gRenderSurfaceW / 2,
@@ -832,7 +840,8 @@
 
     gTorusRotation = 0;
 
-    if (benchMode > gMaxModes) {
+    if (benchMode == gMaxModes) {
+        rsSendToClientBlocking(RS_MSG_RESULTS_READY, gResultBuffer, gMaxModes*sizeof(float));
         benchMode = 0;
         runningLoops++;
         if ((gMaxLoops > 0) && (runningLoops > gMaxLoops) && !sendMsgFlag) {
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/rslist.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/rslist.rs
index aeae13f..d8663fb 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/rslist.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/rslist.rs
@@ -47,7 +47,7 @@
     rsgBindFont(gFont);
 
     rs_allocation listAlloc;
-    rsSetObject(&listAlloc, rsGetAllocation(gList));
+    listAlloc = rsGetAllocation(gList);
     int allocSize = rsAllocationGetDimX(listAlloc);
 
     int width = rsgGetWidth();
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/rstypes.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/rstypes.rs
index f3bf244..22d9c13 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/rstypes.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/rstypes.rs
@@ -48,17 +48,17 @@
 
     struct my_struct structTest;
 
-    rsSetObject(&fontTestLocal, fontTest);
+    fontTestLocal = fontTest;
     //allocationTestLocal = allocationTest;
 
-    rsSetObject(&fontTest, fontTestLocal);
+    fontTest = fontTestLocal;
     //allocationTest = allocationTestLocal;
 
     /*for (int i = 0; i < 4; i++) {
-        rsSetObject(&fontTestLocalArray[i], fontTestLocal);
+        fontTestLocalArray[i] = fontTestLocal;
     }*/
 
-    /*rsSetObject(&fontTest, fontTestLocalArray[3]);*/
+    /*fontTest = fontTestLocalArray[3];*/
 
     return failed;
 }
diff --git a/voip/java/android/net/rtp/package.html b/voip/java/android/net/rtp/package.html
new file mode 100644
index 0000000..4506b09
--- /dev/null
+++ b/voip/java/android/net/rtp/package.html
@@ -0,0 +1,28 @@
+<html>
+<body>
+<p>Provides APIs for RTP (Real-time Transport Protocol), allowing applications to manage on-demand
+or interactive data streaming. In particular, apps that provide VOIP, push-to-talk, conferencing,
+and audio streaming can use these APIs to initiate sessions and transmit or receive data streams
+over any available network.</p>
+
+<p>To support audio conferencing and similar usages, you need to instantiate two classes as
+endpoints for the stream:</p>
+
+<ul>
+<li>{@link android.net.rtp.AudioStream} specifies a remote endpoint and consists of network mapping
+and a configured {@link android.net.rtp.AudioCodec}.</li>
+
+<li>{@link android.net.rtp.AudioGroup} represents the local endpoint for one or more {@link
+android.net.rtp.AudioStream}s. The {@link android.net.rtp.AudioGroup} mixes all the {@link
+android.net.rtp.AudioStream}s and optionally interacts with the device speaker and the microphone at
+the same time.</li>
+</ul>
+
+<p>The simplest usage involves a single remote endpoint and local endpoint. For more complex usages,
+refer to the limitations described for {@link android.net.rtp.AudioGroup}.</p>
+
+<p class="note"><strong>Note:</strong> To use the RTP APIs, you must request the {@link
+android.Manifest.permission#INTERNET} and {@link
+android.Manifest.permission#RECORD_AUDIO} permissions in your manifest file.</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index 6455d84..7f9fc31 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -23,6 +23,7 @@
 import android.net.LinkProperties;
 import android.net.NetworkUtils;
 import android.net.ProxyProperties;
+import android.net.RouteInfo;
 import android.net.wifi.WifiConfiguration.IpAssignment;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiConfiguration.ProxySettings;
@@ -120,7 +121,7 @@
     private static final String ipConfigFile = Environment.getDataDirectory() +
             "/misc/wifi/ipconfig.txt";
 
-    private static final int IPCONFIG_FILE_VERSION = 1;
+    private static final int IPCONFIG_FILE_VERSION = 2;
 
     /* IP and proxy configuration keys */
     private static final String ID_KEY = "id";
@@ -445,9 +446,8 @@
             if (iter.hasNext()) {
                 LinkAddress linkAddress = iter.next();
                 dhcpInfoInternal.ipAddress = linkAddress.getAddress().getHostAddress();
-                Iterator<InetAddress>gateways = linkProperties.getGateways().iterator();
-                if (gateways.hasNext()) {
-                    dhcpInfoInternal.gateway = gateways.next().getHostAddress();
+                for (RouteInfo route : linkProperties.getRoutes()) {
+                    dhcpInfoInternal.addRoute(route);
                 }
                 dhcpInfoInternal.prefixLength = linkAddress.getNetworkPrefixLength();
                 Iterator<InetAddress> dnsIterator = linkProperties.getDnses().iterator();
@@ -604,9 +604,22 @@
                                     out.writeUTF(linkAddr.getAddress().getHostAddress());
                                     out.writeInt(linkAddr.getNetworkPrefixLength());
                                 }
-                                for (InetAddress gateway : linkProperties.getGateways()) {
+                                for (RouteInfo route : linkProperties.getRoutes()) {
                                     out.writeUTF(GATEWAY_KEY);
-                                    out.writeUTF(gateway.getHostAddress());
+                                    LinkAddress dest = route.getDestination();
+                                    if (dest != null) {
+                                        out.writeInt(1);
+                                        out.writeUTF(dest.getAddress().getHostAddress());
+                                        out.writeInt(dest.getNetworkPrefixLength());
+                                    } else {
+                                        out.writeInt(0);
+                                    }
+                                    if (route.getGateway() != null) {
+                                        out.writeInt(1);
+                                        out.writeUTF(route.getGateway().getHostAddress());
+                                    } else {
+                                        out.writeInt(0);
+                                    }
                                 }
                                 for (InetAddress inetAddr : linkProperties.getDnses()) {
                                     out.writeUTF(DNS_KEY);
@@ -682,7 +695,8 @@
             in = new DataInputStream(new BufferedInputStream(new FileInputStream(
                     ipConfigFile)));
 
-            if (in.readInt() != IPCONFIG_FILE_VERSION) {
+            int version = in.readInt();
+            if (version != 2 && version != 1) {
                 Log.e(TAG, "Bad version on IP configuration file, ignore read");
                 return;
             }
@@ -709,8 +723,22 @@
                                     NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt());
                             linkProperties.addLinkAddress(linkAddr);
                         } else if (key.equals(GATEWAY_KEY)) {
-                            linkProperties.addGateway(
-                                    NetworkUtils.numericToInetAddress(in.readUTF()));
+                            LinkAddress dest = null;
+                            InetAddress gateway = null;
+                            if (version == 1) {
+                                // only supported default gateways - leave the dest/prefix empty
+                                gateway = NetworkUtils.numericToInetAddress(in.readUTF());
+                            } else {
+                                if (in.readInt() == 1) {
+                                    dest = new LinkAddress(
+                                            NetworkUtils.numericToInetAddress(in.readUTF()),
+                                            in.readInt());
+                                }
+                                if (in.readInt() == 1) {
+                                    gateway = NetworkUtils.numericToInetAddress(in.readUTF());
+                                }
+                            }
+                            linkProperties.addRoute(new RouteInfo(dest, gateway));
                         } else if (key.equals(DNS_KEY)) {
                             linkProperties.addDns(
                                     NetworkUtils.numericToInetAddress(in.readUTF()));
@@ -1022,22 +1050,21 @@
                         .getLinkAddresses();
                 Collection<InetAddress> currentDnses = currentConfig.linkProperties.getDnses();
                 Collection<InetAddress> newDnses = newConfig.linkProperties.getDnses();
-                Collection<InetAddress> currentGateways =
-                        currentConfig.linkProperties.getGateways();
-                Collection<InetAddress> newGateways = newConfig.linkProperties.getGateways();
+                Collection<RouteInfo> currentRoutes = currentConfig.linkProperties.getRoutes();
+                Collection<RouteInfo> newRoutes = newConfig.linkProperties.getRoutes();
 
                 boolean linkAddressesDiffer =
                         (currentLinkAddresses.size() != newLinkAddresses.size()) ||
                         !currentLinkAddresses.containsAll(newLinkAddresses);
                 boolean dnsesDiffer = (currentDnses.size() != newDnses.size()) ||
                         !currentDnses.containsAll(newDnses);
-                boolean gatewaysDiffer = (currentGateways.size() != newGateways.size()) ||
-                        !currentGateways.containsAll(newGateways);
+                boolean routesDiffer = (currentRoutes.size() != newRoutes.size()) ||
+                        !currentRoutes.containsAll(newRoutes);
 
                 if ((currentConfig.ipAssignment != newConfig.ipAssignment) ||
                         linkAddressesDiffer ||
                         dnsesDiffer ||
-                        gatewaysDiffer) {
+                        routesDiffer) {
                     ipChanged = true;
                 }
                 break;
@@ -1112,8 +1139,8 @@
         for (LinkAddress linkAddr : config.linkProperties.getLinkAddresses()) {
             linkProperties.addLinkAddress(linkAddr);
         }
-        for (InetAddress gateway : config.linkProperties.getGateways()) {
-            linkProperties.addGateway(gateway);
+        for (RouteInfo route : config.linkProperties.getRoutes()) {
+            linkProperties.addRoute(route);
         }
         for (InetAddress dns : config.linkProperties.getDnses()) {
             linkProperties.addDns(dns);
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 33d4e1f..9125037 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -48,6 +48,7 @@
 import android.net.ConnectivityManager;
 import android.net.DhcpInfo;
 import android.net.DhcpInfoInternal;
+import android.net.DhcpStateMachine;
 import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
@@ -152,6 +153,7 @@
     private NetworkInfo mNetworkInfo;
     private SupplicantStateTracker mSupplicantStateTracker;
     private WpsStateMachine mWpsStateMachine;
+    private DhcpStateMachine mDhcpStateMachine;
 
     private AlarmManager mAlarmManager;
     private PendingIntent mScanIntent;
@@ -189,10 +191,10 @@
     static final int CMD_START_DRIVER                     = BASE + 13;
     /* Start the driver */
     static final int CMD_STOP_DRIVER                      = BASE + 14;
-    /* Indicates DHCP succeded */
-    static final int CMD_IP_CONFIG_SUCCESS                = BASE + 15;
-    /* Indicates DHCP failed */
-    static final int CMD_IP_CONFIG_FAILURE                = BASE + 16;
+    /* Indicates Static IP succeded */
+    static final int CMD_STATIC_IP_SUCCESS                = BASE + 15;
+    /* Indicates Static IP failed */
+    static final int CMD_STATIC_IP_FAILURE                = BASE + 16;
 
     /* Start the soft access point */
     static final int CMD_START_AP                         = BASE + 21;
@@ -338,8 +340,11 @@
      */
     private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
 
-    private static final int POWER_MODE_ACTIVE = 1;
-    private static final int POWER_MODE_AUTO = 0;
+    static final int POWER_MODE_ACTIVE = 1;
+    static final int POWER_MODE_AUTO = 0;
+
+    /* Tracks the power mode for restoration after a DHCP request/renewal goes through */
+    private int mPowerMode = POWER_MODE_AUTO;
 
     /**
      * Default framework scan interval in milliseconds. This is used in the scenario in which
@@ -1408,8 +1413,10 @@
          */
         NetworkUtils.resetConnections(mInterfaceName);
 
-        if (!NetworkUtils.stopDhcp(mInterfaceName)) {
-            Log.e(TAG, "Could not stop DHCP");
+        if (mDhcpStateMachine != null) {
+            mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
+            mDhcpStateMachine.quit();
+            mDhcpStateMachine = null;
         }
 
         /* Disable interface */
@@ -1435,6 +1442,100 @@
 
     }
 
+    void handlePreDhcpSetup() {
+        if (!mBluetoothConnectionActive) {
+            /*
+             * There are problems setting the Wi-Fi driver's power
+             * mode to active when bluetooth coexistence mode is
+             * enabled or sense.
+             * <p>
+             * We set Wi-Fi to active mode when
+             * obtaining an IP address because we've found
+             * compatibility issues with some routers with low power
+             * mode.
+             * <p>
+             * In order for this active power mode to properly be set,
+             * we disable coexistence mode until we're done with
+             * obtaining an IP address.  One exception is if we
+             * are currently connected to a headset, since disabling
+             * coexistence would interrupt that connection.
+             */
+            // Disable the coexistence mode
+            WifiNative.setBluetoothCoexistenceModeCommand(
+                    WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
+        }
+
+        mPowerMode =  WifiNative.getPowerModeCommand();
+        if (mPowerMode < 0) {
+            // Handle the case where supplicant driver does not support
+            // getPowerModeCommand.
+            mPowerMode = WifiStateMachine.POWER_MODE_AUTO;
+        }
+        if (mPowerMode != WifiStateMachine.POWER_MODE_ACTIVE) {
+            WifiNative.setPowerModeCommand(WifiStateMachine.POWER_MODE_ACTIVE);
+        }
+    }
+
+
+    void handlePostDhcpSetup() {
+        /* restore power mode */
+        WifiNative.setPowerModeCommand(mPowerMode);
+
+        // Set the coexistence mode back to its default value
+        WifiNative.setBluetoothCoexistenceModeCommand(
+                WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
+    }
+
+    private void handleSuccessfulIpConfiguration(DhcpInfoInternal dhcpInfoInternal) {
+        synchronized (mDhcpInfoInternal) {
+            mDhcpInfoInternal = dhcpInfoInternal;
+        }
+        mLastSignalLevel = -1; // force update of signal strength
+        WifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal);
+        InetAddress addr = NetworkUtils.numericToInetAddress(dhcpInfoInternal.ipAddress);
+        mWifiInfo.setInetAddress(addr);
+        if (getNetworkDetailedState() == DetailedState.CONNECTED) {
+            //DHCP renewal in connected state
+            LinkProperties linkProperties = dhcpInfoInternal.makeLinkProperties();
+            linkProperties.setHttpProxy(WifiConfigStore.getProxyProperties(mLastNetworkId));
+            linkProperties.setInterfaceName(mInterfaceName);
+            if (!linkProperties.equals(mLinkProperties)) {
+                Log.d(TAG, "Link configuration changed for netId: " + mLastNetworkId
+                    + " old: " + mLinkProperties + "new: " + linkProperties);
+                NetworkUtils.resetConnections(mInterfaceName);
+                mLinkProperties = linkProperties;
+                sendLinkConfigurationChangedBroadcast();
+            }
+        } else {
+            configureLinkProperties();
+            setNetworkDetailedState(DetailedState.CONNECTED);
+            sendNetworkStateChangeBroadcast(mLastBssid);
+        }
+    }
+
+    private void handleFailedIpConfiguration() {
+        Log.e(TAG, "IP configuration failed");
+
+        mWifiInfo.setInetAddress(null);
+        /**
+         * If we've exceeded the maximum number of retries for DHCP
+         * to a given network, disable the network
+         */
+        if (++mReconnectCount > getMaxDhcpRetries()) {
+            Log.e(TAG, "Failed " +
+                    mReconnectCount + " times, Disabling " + mLastNetworkId);
+            WifiConfigStore.disableNetwork(mLastNetworkId);
+            mReconnectCount = 0;
+        }
+
+        /* DHCP times out after about 30 seconds, we do a
+         * disconnect and an immediate reconnect to try again
+         */
+        WifiNative.disconnectCommand();
+        WifiNative.reconnectCommand();
+
+    }
+
 
     /*********************************************************
      * Notifications from WifiMonitor
@@ -1606,6 +1707,8 @@
                 case CMD_FORGET_NETWORK:
                 case CMD_RSSI_POLL:
                 case CMD_ENABLE_ALL_NETWORKS:
+                case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+                case DhcpStateMachine.CMD_POST_DHCP_ACTION:
                     break;
                 case CMD_START_WPS:
                     /* Return failure when the state machine cannot handle WPS initiation*/
@@ -2483,74 +2586,18 @@
     }
 
     class ConnectingState extends State {
-        boolean mModifiedBluetoothCoexistenceMode;
-        int mPowerMode;
-        boolean mUseStaticIp;
-        Thread mDhcpThread;
 
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-            mUseStaticIp = WifiConfigStore.isUsingStaticIp(mLastNetworkId);
-            if (!mUseStaticIp) {
-                mDhcpThread = null;
-                mModifiedBluetoothCoexistenceMode = false;
-                mPowerMode = POWER_MODE_AUTO;
 
-                if (!mBluetoothConnectionActive) {
-                    /*
-                     * There are problems setting the Wi-Fi driver's power
-                     * mode to active when bluetooth coexistence mode is
-                     * enabled or sense.
-                     * <p>
-                     * We set Wi-Fi to active mode when
-                     * obtaining an IP address because we've found
-                     * compatibility issues with some routers with low power
-                     * mode.
-                     * <p>
-                     * In order for this active power mode to properly be set,
-                     * we disable coexistence mode until we're done with
-                     * obtaining an IP address.  One exception is if we
-                     * are currently connected to a headset, since disabling
-                     * coexistence would interrupt that connection.
-                     */
-                    mModifiedBluetoothCoexistenceMode = true;
-
-                    // Disable the coexistence mode
-                    WifiNative.setBluetoothCoexistenceModeCommand(
-                            WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
-                }
-
-                mPowerMode =  WifiNative.getPowerModeCommand();
-                if (mPowerMode < 0) {
-                  // Handle the case where supplicant driver does not support
-                  // getPowerModeCommand.
-                    mPowerMode = POWER_MODE_AUTO;
-                }
-                if (mPowerMode != POWER_MODE_ACTIVE) {
-                    WifiNative.setPowerModeCommand(POWER_MODE_ACTIVE);
-                }
-
-                Log.d(TAG, "DHCP request started");
-                mDhcpThread = new Thread(new Runnable() {
-                    public void run() {
-                        DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
-                        if (NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal)) {
-                            Log.d(TAG, "DHCP request succeeded");
-                            synchronized (mDhcpInfoInternal) {
-                                mDhcpInfoInternal = dhcpInfoInternal;
-                            }
-                            WifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal);
-                            sendMessage(CMD_IP_CONFIG_SUCCESS);
-                        } else {
-                            Log.d(TAG, "DHCP request failed: " +
-                                    NetworkUtils.getDhcpError());
-                            sendMessage(CMD_IP_CONFIG_FAILURE);
-                        }
-                    }
-                });
-                mDhcpThread.start();
+             if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
+                //start DHCP
+                mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
+                        mContext, WifiStateMachine.this, mInterfaceName);
+                mDhcpStateMachine.registerForPreDhcpNotification();
+                mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
             } else {
                 DhcpInfoInternal dhcpInfoInternal = WifiConfigStore.getIpConfiguration(
                         mLastNetworkId);
@@ -2562,16 +2609,13 @@
                 try {
                     netd.setInterfaceConfig(mInterfaceName, ifcg);
                     Log.v(TAG, "Static IP configuration succeeded");
-                    synchronized (mDhcpInfoInternal) {
-                        mDhcpInfoInternal = dhcpInfoInternal;
-                    }
-                    sendMessage(CMD_IP_CONFIG_SUCCESS);
+                    sendMessage(CMD_STATIC_IP_SUCCESS, dhcpInfoInternal);
                 } catch (RemoteException re) {
                     Log.v(TAG, "Static IP configuration failed: " + re);
-                    sendMessage(CMD_IP_CONFIG_FAILURE);
+                    sendMessage(CMD_STATIC_IP_FAILURE);
                 } catch (IllegalStateException e) {
                     Log.v(TAG, "Static IP configuration failed: " + e);
-                    sendMessage(CMD_IP_CONFIG_FAILURE);
+                    sendMessage(CMD_STATIC_IP_FAILURE);
                 }
             }
          }
@@ -2580,44 +2624,26 @@
           if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
 
           switch(message.what) {
-              case CMD_IP_CONFIG_SUCCESS:
-                  mLastSignalLevel = -1; // force update of signal strength
-                  InetAddress addr;
-                  synchronized (mDhcpInfoInternal) {
-                      addr = NetworkUtils.numericToInetAddress(mDhcpInfoInternal.ipAddress);
+              case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+                  handlePreDhcpSetup();
+                  mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
+                  break;
+              case DhcpStateMachine.CMD_POST_DHCP_ACTION:
+                  handlePostDhcpSetup();
+                  if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
+                      handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
+                      transitionTo(mConnectedState);
+                  } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
+                      handleFailedIpConfiguration();
+                      transitionTo(mDisconnectingState);
                   }
-                  mWifiInfo.setInetAddress(addr);
-                  configureLinkProperties();
-                  if (getNetworkDetailedState() == DetailedState.CONNECTED) {
-                      sendLinkConfigurationChangedBroadcast();
-                  } else {
-                      setNetworkDetailedState(DetailedState.CONNECTED);
-                      sendNetworkStateChangeBroadcast(mLastBssid);
-                  }
-                  //TODO: The framework is not detecting a DHCP renewal and a possible
-                  //IP change. we should detect this and send out a config change broadcast
+                  break;
+              case CMD_STATIC_IP_SUCCESS:
+                  handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
                   transitionTo(mConnectedState);
                   break;
-              case CMD_IP_CONFIG_FAILURE:
-                  mWifiInfo.setInetAddress(null);
-
-                  Log.e(TAG, "IP configuration failed");
-                  /**
-                   * If we've exceeded the maximum number of retries for DHCP
-                   * to a given network, disable the network
-                   */
-                  if (++mReconnectCount > getMaxDhcpRetries()) {
-                      Log.e(TAG, "Failed " +
-                              mReconnectCount + " times, Disabling " + mLastNetworkId);
-                      WifiConfigStore.disableNetwork(mLastNetworkId);
-                      mReconnectCount = 0;
-                  }
-
-                  /* DHCP times out after about 30 seconds, we do a
-                   * disconnect and an immediate reconnect to try again
-                   */
-                  WifiNative.disconnectCommand();
-                  WifiNative.reconnectCommand();
+              case CMD_STATIC_IP_FAILURE:
+                  handleFailedIpConfiguration();
                   transitionTo(mDisconnectingState);
                   break;
               case CMD_DISCONNECT:
@@ -2661,23 +2687,6 @@
           EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
           return HANDLED;
       }
-
-      @Override
-      public void exit() {
-          /* reset power state & bluetooth coexistence if on DHCP */
-          if (!mUseStaticIp) {
-              if (mPowerMode != POWER_MODE_ACTIVE) {
-                  WifiNative.setPowerModeCommand(mPowerMode);
-              }
-
-              if (mModifiedBluetoothCoexistenceMode) {
-                  // Set the coexistence mode back to its default value
-                  WifiNative.setBluetoothCoexistenceModeCommand(
-                          WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
-              }
-          }
-
-      }
     }
 
     class ConnectedState extends State {
@@ -2695,6 +2704,19 @@
             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
             boolean eventLoggingEnabled = true;
             switch (message.what) {
+              case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+                  handlePreDhcpSetup();
+                  mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
+                  break;
+              case DhcpStateMachine.CMD_POST_DHCP_ACTION:
+                  handlePostDhcpSetup();
+                  if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
+                      handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
+                  } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
+                      handleFailedIpConfiguration();
+                      transitionTo(mDisconnectingState);
+                  }
+                  break;
                 case CMD_DISCONNECT:
                     WifiNative.disconnectCommand();
                     transitionTo(mDisconnectingState);