Merge "Improve camera javadoc."
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 a7f0368..950c130 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -21725,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/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/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/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/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/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 984102a..2b79a76 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -261,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/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 7ca6e09..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
  */
@@ -209,7 +209,7 @@
     
     /**
      * 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()}.
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/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 7838ec0..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)
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 ade3a0a..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;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 24b176d..359cfcc 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.
@@ -8290,7 +8290,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/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java
index 3979eab..7830dca 100644
--- a/core/java/com/android/internal/widget/AbsActionBarView.java
+++ b/core/java/com/android/internal/widget/AbsActionBarView.java
@@ -76,6 +76,7 @@
                 splitAnim.setDuration(FADE_DURATION);
                 set.addListener(mVisAnimListener.withFinalVisibility(visibility));
                 set.play(anim).with(splitAnim);
+                set.start();
             } else {
                 anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
                 anim.start();
@@ -90,6 +91,7 @@
                 splitAnim.setDuration(FADE_DURATION);
                 set.addListener(mVisAnimListener.withFinalVisibility(visibility));
                 set.play(anim).with(splitAnim);
+                set.start();
             } else {
                 anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
                 anim.start();
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index f45a3bb..c82323e 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -428,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 d6f439a..13ccbba 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -228,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);
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 95224a4..8beb94b 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -48,7 +48,7 @@
 	android_view_Display.cpp \
 	android_view_Surface.cpp \
 	android_view_TextureView.cpp \
-	android_view_ViewRoot.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 c915753..17f9246 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -119,7 +119,7 @@
 extern int register_android_view_GLES20Canvas(JNIEnv* env);
 extern int register_android_view_Surface(JNIEnv* env);
 extern int register_android_view_TextureView(JNIEnv* env);
-extern int register_android_view_ViewRoot(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);
@@ -1124,7 +1124,7 @@
     REG_JNI(register_android_view_GLES20Canvas),
     REG_JNI(register_android_view_Surface),
     REG_JNI(register_android_view_TextureView),
-    REG_JNI(register_android_view_ViewRoot),
+    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_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 f929a0e..d43a27f 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -519,6 +519,11 @@
     return redraw;
 }
 
+static void android_view_GLES20Canvas_outputDisplayList(JNIEnv* env,
+        jobject clazz, OpenGLRenderer* renderer, DisplayList* displayList) {
+    renderer->outputDisplayList(displayList);
+}
+
 // ----------------------------------------------------------------------------
 // Layers
 // ----------------------------------------------------------------------------
@@ -714,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 },
 
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/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/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/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/styles.xml b/core/res/res/values/styles.xml
index dbb8d37..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>
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/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..5b8aa7a 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -301,6 +301,17 @@
       <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 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>
             <span class="new">new!</span>
@@ -347,7 +358,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>
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/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/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/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/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/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/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 6f751e8..f6a21d4 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1185,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;
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index b5c37c2..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);
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 6d63f67..e2e14f2 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -270,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);
diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp
index 28fa061..c0fa95b 100644
--- a/libs/rs/rsProgram.cpp
+++ b/libs/rs/rsProgram.cpp
@@ -49,7 +49,6 @@
     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) {
@@ -154,7 +153,6 @@
         return;
     }
 
-    //LOGE("bindtex %i %p", slot, a);
     mHal.state.textures[slot].set(a);
     mDirty = true;
 }
@@ -170,10 +168,6 @@
     mDirty = true;
 }
 
-void Program::setShader(const char *txt, uint32_t len) {
-    mUserShader.setTo(txt, len);
-}
-
 namespace android {
 namespace renderscript {
 
diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h
index bcf5519..2922270 100644
--- a/libs/rs/rsProgram.h
+++ b/libs/rs/rsProgram.h
@@ -43,8 +43,6 @@
     void bindTexture(Context *, uint32_t slot, Allocation *);
     void bindSampler(Context *, uint32_t slot, Sampler *);
 
-    void setShader(const char *, uint32_t len);
-
     void forceDirty() const {mDirty = true;}
 
     struct Hal {
diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp
index 39887ca..fcbfbc8 100644
--- a/libs/rs/rsProgramFragment.cpp
+++ b/libs/rs/rsProgramFragment.cpp
@@ -56,7 +56,6 @@
 }
 
 void ProgramFragment::setupGL2(Context *rsc, ProgramFragmentState *state) {
-    //LOGE("sgl2 frag1 %x", glGetError());
     if ((state->mLast.get() == this) && !mDirty) {
         return;
     }
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index dfd732f..b8b3c0b 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -37,8 +37,6 @@
         return;
     }
 
-    rsc->checkError("ProgramVertex::setupGL2 start");
-
     if (!isUserProgram()) {
         if (mHal.state.constants[0].get() == NULL) {
             rsc->setError(RS_ERROR_FATAL_UNKNOWN,
@@ -59,8 +57,6 @@
     state->mLast.set(this);
 
     rsc->mHal.funcs.vertex.setActive(rsc, this);
-
-    rsc->checkError("ProgramVertex::setupGL2");
 }
 
 void ProgramVertex::setProjectionMatrix(Context *rsc, const rsc_Matrix *m) const {
diff --git a/libs/rs/rsSampler.cpp b/libs/rs/rsSampler.cpp
index db2383a..670d07e 100644
--- a/libs/rs/rsSampler.cpp
+++ b/libs/rs/rsSampler.cpp
@@ -39,12 +39,12 @@
                  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;
 }
 
 Sampler::~Sampler() {
@@ -76,35 +76,35 @@
         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]);
+                glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[mHal.state.minFilter]);
             } else {
-                switch (trans[mMinFilter]) {
+                switch (trans[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[mMinFilter]);
+                    glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[mHal.state.minFilter]);
                     break;
                 }
             }
         } else {
-            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[mMinFilter]);
+            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[mHal.state.minFilter]);
         }
-        glTexParameteri(target, GL_TEXTURE_MAG_FILTER, transNP[mMagFilter]);
-        glTexParameteri(target, GL_TEXTURE_WRAP_S, transNP[mWrapS]);
-        glTexParameteri(target, GL_TEXTURE_WRAP_T, transNP[mWrapT]);
+        glTexParameteri(target, GL_TEXTURE_MAG_FILTER, transNP[mHal.state.magFilter]);
+        glTexParameteri(target, GL_TEXTURE_WRAP_S, transNP[mHal.state.wrapS]);
+        glTexParameteri(target, GL_TEXTURE_WRAP_T, transNP[mHal.state.wrapT]);
     } else {
         if (tex->getHasGraphicsMipmaps()) {
-            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]);
+            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[mHal.state.minFilter]);
         } else {
-            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[mMinFilter]);
+            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[mHal.state.minFilter]);
         }
-        glTexParameteri(target, GL_TEXTURE_MAG_FILTER, trans[mMagFilter]);
-        glTexParameteri(target, GL_TEXTURE_WRAP_S, trans[mWrapS]);
-        glTexParameteri(target, GL_TEXTURE_WRAP_T, trans[mWrapT]);
+        glTexParameteri(target, GL_TEXTURE_MAG_FILTER, trans[mHal.state.magFilter]);
+        glTexParameteri(target, GL_TEXTURE_WRAP_S, trans[mHal.state.wrapS]);
+        glTexParameteri(target, GL_TEXTURE_WRAP_T, trans[mHal.state.wrapT]);
     }
 
-    float anisoValue = rsMin(rsc->ext_texture_max_aniso(), mAniso);
+    float anisoValue = rsMin(rsc->ext_texture_max_aniso(), mHal.state.aniso);
     if (rsc->ext_texture_max_aniso() > 1.0f) {
         glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoValue);
     }
@@ -135,66 +135,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..192ee07 100644
--- a/libs/rs/rsSampler.h
+++ b/libs/rs/rsSampler.h
@@ -50,14 +50,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 +75,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/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/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/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/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/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/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/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/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 5d20e6a..d997109 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1524,6 +1524,7 @@
             }
 
             st.onRestoreInstanceState(icicles.get(curFeatureId));
+            invalidatePanelMenu(curFeatureId);
         }
 
         /*
@@ -3115,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;
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/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 c225e89..7272e76 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -709,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()) {
@@ -1662,7 +1666,7 @@
         }
     }
 
-    private int getRestoreDefaultNetworkDelay() {
+    private int getRestoreDefaultNetworkDelay(int networkType) {
         String restoreDefaultNetworkDelayStr = SystemProperties.get(
                 NETWORK_RESTORE_DELAY_PROP_NAME);
         if(restoreDefaultNetworkDelayStr != null &&
@@ -1672,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/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 ad6ab8e..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();
@@ -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;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3eb4c11..1e16943 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -325,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/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/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 6a5b82c..c4359a9 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -490,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);
 
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index ad4e796..244f35e 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -38,6 +38,7 @@
 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;
 
@@ -143,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;
@@ -202,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;
@@ -275,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();
@@ -300,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) {
@@ -329,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;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 4b185a0..f325812 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -54,9 +54,6 @@
 
     private CDMAPhone mCdmaPhone;
 
-    //useful for debugging
-    boolean mFailNextConnect = false;
-
     /** The DataConnection being setup */
     private CdmaDataConnection mPendingDataConnection;
 
@@ -660,7 +657,7 @@
             reason = (String) ar.userObj;
         }
 
-        if (ar.exception == null) {
+        if (isDataSetupCompleteOk(ar)) {
             // Everything is setup
             notifyDefaultData(reason);
         } else {
@@ -704,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);
       }
     }
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index a1b4376..d3e659a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -101,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
 
@@ -1574,13 +1569,14 @@
         } else {
             throw new RuntimeException("onDataSetupComplete: No apnContext");
         }
-        DataConnectionAc dcac = apnContext.getDataConnectionAc();
-        if (dcac == null) {
-            throw new RuntimeException("onDataSetupCompete: No dcac");
-        }
-        DataConnection dc = apnContext.getDataConnection();
 
-        if (ar.exception == null) {
+        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) + " refCount=" + dc.getRefCount());
@@ -1612,16 +1608,11 @@
             }
             notifyDefaultData(apnContext);
         } else {
-            int refCount = releaseApnContext(apnContext, false);
-            if (DBG) {
-                log(String.format("onDataSetupComplete: error apn=%s",
-                    apnContext.getWaitingApns().get(0).apn) + " refCount=" + refCount);
-            }
+            String apnString;
+            DataConnection.FailCause cause;
 
-            GsmDataConnection.FailCause cause;
-            cause = (GsmDataConnection.FailCause) (ar.result);
+            cause = (DataConnection.FailCause) (ar.result);
             if (DBG) {
-                String apnString;
                 try {
                     apnString = apnContext.getWaitingApns().get(0).apn;
                 } catch (Exception e) {
@@ -1667,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);
+            }
         }
     }
 
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 91bac88..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;
@@ -168,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,
@@ -638,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;
     }
@@ -782,9 +793,10 @@
         return 1;
     }
 
+    gDt = 1.0f / 60.0f;
+
     rsgFinish();
     int64_t start = rsUptimeMillis();
-    rsGetDt();
 
     int drawPos = 0;
     int frameCount = 100;
@@ -801,7 +813,6 @@
         gRenderSurfaceH = rsgGetHeight();
         int size = 8;
         drawOffscreenResult((drawPos+=size)%gRenderSurfaceW, (gRenderSurfaceH * 3) / 4, size, size);
-        gDt = rsGetDt();
     }
 
     rsgFinish();
@@ -809,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,
@@ -828,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/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