am 3a735078: Merge "SurfaceTexture: report binder transaction failures" into ics-mr0

* commit '3a73507801b56da83140fad14a1a3d4eced213d9':
  SurfaceTexture: report binder transaction failures
diff --git a/api/current.txt b/api/current.txt
index 92969f6..ffa46ec 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6782,6 +6782,13 @@
     method public abstract boolean onMove(int, int);
   }
 
+  public class CrossProcessCursorWrapper extends android.database.CursorWrapper implements android.database.CrossProcessCursor {
+    ctor public CrossProcessCursorWrapper(android.database.Cursor);
+    method public void fillWindow(int, android.database.CursorWindow);
+    method public android.database.CursorWindow getWindow();
+    method public boolean onMove(int, int);
+  }
+
   public abstract interface Cursor {
     method public abstract void close();
     method public abstract void copyStringToBuffer(int, android.database.CharArrayBuffer);
@@ -6851,7 +6858,8 @@
   }
 
   public class CursorWindow extends android.database.sqlite.SQLiteClosable implements android.os.Parcelable {
-    ctor public CursorWindow(boolean);
+    ctor public CursorWindow(java.lang.String);
+    ctor public deprecated CursorWindow(boolean);
     method public boolean allocRow();
     method public void clear();
     method public void close();
@@ -24082,6 +24090,8 @@
     method public int getCurrentItemIndex();
     method public int getFromIndex();
     method public int getItemCount();
+    method public int getMaxScrollX();
+    method public int getMaxScrollY();
     method public android.os.Parcelable getParcelableData();
     method public int getRemovedCount();
     method public int getScrollX();
@@ -24108,6 +24118,8 @@
     method public void setFromIndex(int);
     method public void setFullScreen(boolean);
     method public void setItemCount(int);
+    method public void setMaxScrollX(int);
+    method public void setMaxScrollY(int);
     method public void setParcelableData(android.os.Parcelable);
     method public void setPassword(boolean);
     method public void setRemovedCount(int);
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 528d197..7cb8f62 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -30,7 +30,6 @@
 #include <binder/ProcessState.h>
 #include <media/IMediaPlayerService.h>
 #include <media/stagefright/foundation/ALooper.h>
-#include "include/ARTSPController.h"
 #include "include/LiveSession.h"
 #include "include/NuCachedSource2.h"
 #include <media/stagefright/AudioPlayer.h>
@@ -636,7 +635,6 @@
     gDisplayHistogram = false;
 
     sp<ALooper> looper;
-    sp<ARTSPController> rtspController;
     sp<LiveSession> liveSession;
 
     int res;
@@ -948,7 +946,6 @@
         sp<DataSource> dataSource = DataSource::CreateFromURI(filename);
 
         if (strncasecmp(filename, "sine:", 5)
-                && strncasecmp(filename, "rtsp://", 7)
                 && strncasecmp(filename, "httplive://", 11)
                 && dataSource == NULL) {
             fprintf(stderr, "Unable to create data source.\n");
@@ -984,23 +981,7 @@
         } else {
             sp<MediaExtractor> extractor;
 
-            if (!strncasecmp("rtsp://", filename, 7)) {
-                if (looper == NULL) {
-                    looper = new ALooper;
-                    looper->start();
-                }
-
-                rtspController = new ARTSPController(looper);
-                status_t err = rtspController->connect(filename);
-                if (err != OK) {
-                    fprintf(stderr, "could not connect to rtsp server.\n");
-                    return -1;
-                }
-
-                extractor = rtspController.get();
-
-                syncInfoPresent = false;
-            } else if (!strncasecmp("httplive://", filename, 11)) {
+            if (!strncasecmp("httplive://", filename, 11)) {
                 String8 uri("http://");
                 uri.append(filename + 11);
 
@@ -1021,6 +1002,7 @@
                 syncInfoPresent = false;
             } else {
                 extractor = MediaExtractor::Create(dataSource);
+
                 if (extractor == NULL) {
                     fprintf(stderr, "could not create extractor.\n");
                     return -1;
@@ -1116,13 +1098,6 @@
         } else {
             playSource(&client, mediaSource);
         }
-
-        if (rtspController != NULL) {
-            rtspController->disconnect();
-            rtspController.clear();
-
-            sleep(3);
-        }
     }
 
     if ((useSurfaceAlloc || useSurfaceTexAlloc) && !audioOnly) {
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 3290b9d..3aa159e 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -24,6 +24,7 @@
 import android.content.Intent;
 import android.content.pm.ResolveInfo;
 import android.database.Cursor;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -498,8 +499,24 @@
                             ComponentName launchActivity,
                             Bundle appSearchData,
                             boolean globalSearch) {
+        startSearch(initialQuery, selectInitialQuery, launchActivity,
+                appSearchData, globalSearch, null);
+    }
+
+    /**
+     * As {@link #startSearch(String, boolean, ComponentName, Bundle, boolean)} but including
+     * source bounds for the global search intent.
+     *
+     * @hide
+     */
+    public void startSearch(String initialQuery,
+                            boolean selectInitialQuery,
+                            ComponentName launchActivity,
+                            Bundle appSearchData,
+                            boolean globalSearch,
+                            Rect sourceBounds) {
         if (globalSearch) {
-            startGlobalSearch(initialQuery, selectInitialQuery, appSearchData);
+            startGlobalSearch(initialQuery, selectInitialQuery, appSearchData, sourceBounds);
             return;
         }
 
@@ -520,7 +537,7 @@
      * Starts the global search activity.
      */
     /* package */ void startGlobalSearch(String initialQuery, boolean selectInitialQuery,
-            Bundle appSearchData) {
+            Bundle appSearchData, Rect sourceBounds) {
         ComponentName globalSearchActivity = getGlobalSearchActivity();
         if (globalSearchActivity == null) {
             Log.w(TAG, "No global search activity found.");
@@ -546,6 +563,7 @@
         if (selectInitialQuery) {
             intent.putExtra(EXTRA_SELECT_QUERY, selectInitialQuery);
         }
+        intent.setSourceBounds(sourceBounds);
         try {
             if (DBG) Log.d(TAG, "Starting global search: " + intent.toUri(0));
             mContext.startActivity(intent);
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index e923349..cc3219b 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -26,6 +26,7 @@
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
 import android.database.ContentObserver;
+import android.database.CrossProcessCursorWrapper;
 import android.database.Cursor;
 import android.database.CursorWrapper;
 import android.database.IContentObserver;
@@ -1568,7 +1569,7 @@
             samplePercent);
     }
 
-    private final class CursorWrapperInner extends CursorWrapper {
+    private final class CursorWrapperInner extends CrossProcessCursorWrapper {
         private final IContentProvider mContentProvider;
         public static final String TAG="CursorWrapperInner";
 
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index ee6aec6..74fef29 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -53,7 +53,10 @@
     abstract public boolean isNull(int column);
 
     public int getType(int column) {
-        throw new UnsupportedOperationException();
+        // Reflects the assumption that all commonly used field types (meaning everything
+        // but blobs) are convertible to strings so it should be safe to call
+        // getString to retrieve them.
+        return FIELD_TYPE_STRING;
     }
 
     // TODO implement getBlob in all cursor types
@@ -185,46 +188,9 @@
         return result;
     }
 
-    /**
-     * Copy data from cursor to CursorWindow
-     * @param position start position of data
-     * @param window
-     */
+    @Override
     public void fillWindow(int position, CursorWindow window) {
-        if (position < 0 || position >= getCount()) {
-            return;
-        }
-        window.acquireReference();
-        try {
-            int oldpos = mPos;
-            mPos = position - 1;
-            window.clear();
-            window.setStartPosition(position);
-            int columnNum = getColumnCount();
-            window.setNumColumns(columnNum);
-            while (moveToNext() && window.allocRow()) {
-                for (int i = 0; i < columnNum; i++) {
-                    String field = getString(i);
-                    if (field != null) {
-                        if (!window.putString(field, mPos, i)) {
-                            window.freeLastRow();
-                            break;
-                        }
-                    } else {
-                        if (!window.putNull(mPos, i)) {
-                            window.freeLastRow();
-                            break;
-                        }
-                    }
-                }
-            }
-
-            mPos = oldpos;
-        } catch (IllegalStateException e){
-            // simply ignore it
-        } finally {
-            window.releaseReference();
-        }
+        DatabaseUtils.cursorFillWindow(this, position, window);
     }
 
     public final boolean move(int offset) {
diff --git a/core/java/android/database/AbstractWindowedCursor.java b/core/java/android/database/AbstractWindowedCursor.java
index d0aedd2..083485f 100644
--- a/core/java/android/database/AbstractWindowedCursor.java
+++ b/core/java/android/database/AbstractWindowedCursor.java
@@ -188,15 +188,14 @@
 
     /**
      * If there is a window, clear it.
-     * Otherwise, creates a local window.
+     * Otherwise, creates a new window.
      *
      * @param name The window name.
      * @hide
      */
-    protected void clearOrCreateLocalWindow(String name) {
+    protected void clearOrCreateWindow(String name) {
         if (mWindow == null) {
-            // If there isn't a window set already it will only be accessed locally
-            mWindow = new CursorWindow(name, true /* the window is local only */);
+            mWindow = new CursorWindow(name);
         } else {
             mWindow.clear();
         }
diff --git a/core/java/android/database/CrossProcessCursor.java b/core/java/android/database/CrossProcessCursor.java
index 8e6a5aa..26379cc 100644
--- a/core/java/android/database/CrossProcessCursor.java
+++ b/core/java/android/database/CrossProcessCursor.java
@@ -16,27 +16,63 @@
 
 package android.database;
 
+/**
+ * A cross process cursor is an extension of a {@link Cursor} that also supports
+ * usage from remote processes.
+ * <p>
+ * The contents of a cross process cursor are marshalled to the remote process by
+ * filling {@link CursorWindow} objects using {@link #fillWindow}.  As an optimization,
+ * the cursor can provide a pre-filled window to use via {@link #getWindow} thereby
+ * obviating the need to copy the data to yet another cursor window.
+ */
 public interface CrossProcessCursor extends Cursor {
     /**
-     * returns a pre-filled window, return NULL if no such window
+     * Returns a pre-filled window that contains the data within this cursor.
+     * <p>
+     * In particular, the window contains the row indicated by {@link Cursor#getPosition}.
+     * The window's contents are automatically scrolled whenever the current
+     * row moved outside the range covered by the window.
+     * </p>
+     *
+     * @return The pre-filled window, or null if none.
      */
     CursorWindow getWindow();
 
     /**
-     * copies cursor data into the window start at pos
+     * Copies cursor data into the window.
+     * <p>
+     * Clears the window and fills it with data beginning at the requested
+     * row position until all of the data in the cursor is exhausted
+     * or the window runs out of space.
+     * </p><p>
+     * The filled window uses the same row indices as the original cursor.
+     * For example, if you fill a window starting from row 5 from the cursor,
+     * you can query the contents of row 5 from the window just by asking it
+     * for row 5 because there is a direct correspondence between the row indices
+     * used by the cursor and the window.
+     * </p><p>
+     * The current position of the cursor, as returned by {@link #getPosition},
+     * is not changed by this method.
+     * </p>
+     *
+     * @param position The zero-based index of the first row to copy into the window.
+     * @param window The window to fill.
      */
-    void fillWindow(int pos, CursorWindow winow);
+    void fillWindow(int position, CursorWindow window);
 
     /**
      * This function is called every time the cursor is successfully scrolled
      * to a new position, giving the subclass a chance to update any state it
-     * may have. If it returns false the move function will also do so and the
+     * may have.  If it returns false the move function will also do so and the
      * cursor will scroll to the beforeFirst position.
+     * <p>
+     * This function should be called by methods such as {@link #moveToPosition(int)},
+     * so it will typically not be called from outside of the cursor class itself.
+     * </p>
      *
-     * @param oldPosition the position that we're moving from
-     * @param newPosition the position that we're moving to
-     * @return true if the move is successful, false otherwise
+     * @param oldPosition The position that we're moving from.
+     * @param newPosition The position that we're moving to.
+     * @return True if the move is successful, false otherwise.
      */
     boolean onMove(int oldPosition, int newPosition); 
-    
 }
diff --git a/core/java/android/database/CrossProcessCursorWrapper.java b/core/java/android/database/CrossProcessCursorWrapper.java
new file mode 100644
index 0000000..8c250b8
--- /dev/null
+++ b/core/java/android/database/CrossProcessCursorWrapper.java
@@ -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
+ */
+
+package android.database;
+
+import android.database.CrossProcessCursor;
+import android.database.Cursor;
+import android.database.CursorWindow;
+import android.database.CursorWrapper;
+
+/**
+ * Cursor wrapper that implements {@link CrossProcessCursor}.
+ * <p>
+ * If the wrapper cursor implemented {@link CrossProcessCursor}, then delegates
+ * {@link #fillWindow}, {@link #getWindow()} and {@link #onMove} to it.  Otherwise,
+ * provides default implementations of these methods that traverse the contents
+ * of the cursor similar to {@link AbstractCursor#fillWindow}.
+ * </p><p>
+ * This wrapper can be used to adapt an ordinary {@link Cursor} into a
+ * {@link CrossProcessCursor}.
+ * </p>
+ */
+public class CrossProcessCursorWrapper extends CursorWrapper implements CrossProcessCursor {
+    /**
+     * Creates a cross process cursor wrapper.
+     * @param cursor The underlying cursor to wrap.
+     */
+    public CrossProcessCursorWrapper(Cursor cursor) {
+        super(cursor);
+    }
+
+    @Override
+    public void fillWindow(int position, CursorWindow window) {
+        if (mCursor instanceof CrossProcessCursor) {
+            final CrossProcessCursor crossProcessCursor = (CrossProcessCursor)mCursor;
+            crossProcessCursor.fillWindow(position, window);
+            return;
+        }
+
+        DatabaseUtils.cursorFillWindow(mCursor, position, window);
+    }
+
+    @Override
+    public CursorWindow getWindow() {
+        if (mCursor instanceof CrossProcessCursor) {
+            final CrossProcessCursor crossProcessCursor = (CrossProcessCursor)mCursor;
+            return crossProcessCursor.getWindow();
+        }
+
+        return null;
+    }
+
+    @Override
+    public boolean onMove(int oldPosition, int newPosition) {
+        if (mCursor instanceof CrossProcessCursor) {
+            final CrossProcessCursor crossProcessCursor = (CrossProcessCursor)mCursor;
+            return crossProcessCursor.onMove(oldPosition, newPosition);
+        }
+
+        return true;
+    }
+}
diff --git a/core/java/android/database/CursorToBulkCursorAdaptor.java b/core/java/android/database/CursorToBulkCursorAdaptor.java
index dd2c9b7..215035d 100644
--- a/core/java/android/database/CursorToBulkCursorAdaptor.java
+++ b/core/java/android/database/CursorToBulkCursorAdaptor.java
@@ -25,9 +25,9 @@
 /**
  * Wraps a BulkCursor around an existing Cursor making it remotable.
  * <p>
- * If the wrapped cursor is a {@link AbstractWindowedCursor} then it owns
- * the cursor window.  Otherwise, the adaptor takes ownership of the
- * cursor itself and ensures it gets closed as needed during deactivation
+ * If the wrapped cursor returns non-null from {@link CrossProcessCursor#getWindow}
+ * then it is assumed to own the window.  Otherwise, the adaptor provides a
+ * window to be filled and ensures it gets closed as needed during deactivation
  * and requeries.
  * </p>
  *
@@ -48,12 +48,11 @@
     private CrossProcessCursor mCursor;
 
     /**
-     * The cursor window used by the cross process cursor.
-     * This field is always null for abstract windowed cursors since they are responsible
-     * for managing the lifetime of their window.
+     * The cursor window that was filled by the cross process cursor in the
+     * case where the cursor does not support getWindow.
+     * This field is only ever non-null when the window has actually be filled.
      */
-    private CursorWindow mWindowForNonWindowedCursor;
-    private boolean mWindowForNonWindowedCursorWasFilled;
+    private CursorWindow mFilledWindow;
 
     private static final class ContentObserverProxy extends ContentObserver {
         protected IContentObserver mRemote;
@@ -90,11 +89,10 @@
 
     public CursorToBulkCursorAdaptor(Cursor cursor, IContentObserver observer,
             String providerName) {
-        try {
-            mCursor = (CrossProcessCursor) cursor;
-        } catch (ClassCastException e) {
-            throw new UnsupportedOperationException(
-                    "Only CrossProcessCursor cursors are supported across process for now", e);
+        if (cursor instanceof CrossProcessCursor) {
+            mCursor = (CrossProcessCursor)cursor;
+        } else {
+            mCursor = new CrossProcessCursorWrapper(cursor);
         }
         mProviderName = providerName;
 
@@ -103,11 +101,10 @@
         }
     }
 
-    private void closeWindowForNonWindowedCursorLocked() {
-        if (mWindowForNonWindowedCursor != null) {
-            mWindowForNonWindowedCursor.close();
-            mWindowForNonWindowedCursor = null;
-            mWindowForNonWindowedCursorWasFilled = false;
+    private void closeFilledWindowLocked() {
+        if (mFilledWindow != null) {
+            mFilledWindow.close();
+            mFilledWindow = null;
         }
     }
 
@@ -118,7 +115,7 @@
             mCursor = null;
         }
 
-        closeWindowForNonWindowedCursorLocked();
+        closeFilledWindowLocked();
     }
 
     private void throwIfCursorIsClosed() {
@@ -139,30 +136,24 @@
         synchronized (mLock) {
             throwIfCursorIsClosed();
 
-            CursorWindow window;
-            if (mCursor instanceof AbstractWindowedCursor) {
-                AbstractWindowedCursor windowedCursor = (AbstractWindowedCursor)mCursor;
-                window = windowedCursor.getWindow();
-                if (window == null) {
-                    window = new CursorWindow(mProviderName, false /*localOnly*/);
-                    windowedCursor.setWindow(window);
-                }
+            if (!mCursor.moveToPosition(startPos)) {
+                closeFilledWindowLocked();
+                return null;
+            }
 
-                mCursor.moveToPosition(startPos);
+            CursorWindow window = mCursor.getWindow();
+            if (window != null) {
+                closeFilledWindowLocked();
             } else {
-                window = mWindowForNonWindowedCursor;
+                window = mFilledWindow;
                 if (window == null) {
-                    window = new CursorWindow(mProviderName, false /*localOnly*/);
-                    mWindowForNonWindowedCursor = window;
-                }
-
-                mCursor.moveToPosition(startPos);
-
-                if (!mWindowForNonWindowedCursorWasFilled
-                        || startPos < window.getStartPosition()
-                        || startPos >= window.getStartPosition() + window.getNumRows()) {
+                    mFilledWindow = new CursorWindow(mProviderName);
+                    window = mFilledWindow;
                     mCursor.fillWindow(startPos, window);
-                    mWindowForNonWindowedCursorWasFilled = true;
+                } else if (startPos < window.getStartPosition()
+                        || startPos >= window.getStartPosition() + window.getNumRows()) {
+                    window.clear();
+                    mCursor.fillWindow(startPos, window);
                 }
             }
 
@@ -211,7 +202,7 @@
                 mCursor.deactivate();
             }
 
-            closeWindowForNonWindowedCursorLocked();
+            closeFilledWindowLocked();
         }
     }
 
@@ -227,7 +218,7 @@
         synchronized (mLock) {
             throwIfCursorIsClosed();
 
-            closeWindowForNonWindowedCursorLocked();
+            closeFilledWindowLocked();
 
             try {
                 if (!mCursor.requery()) {
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index a18a721..9c93324 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -31,8 +31,8 @@
 /**
  * A buffer containing multiple cursor rows.
  * <p>
- * A {@link CursorWindow} is read-write when created and used locally.  When sent
- * to a remote process (by writing it to a {@link Parcel}), the remote process
+ * A {@link CursorWindow} is read-write when initially created and used locally.
+ * When sent to a remote process (by writing it to a {@link Parcel}), the remote process
  * receives a read-only view of the cursor window.  Typically the cursor window
  * will be allocated by the producer, filled with data, and then sent to the
  * consumer for reading.
@@ -58,8 +58,7 @@
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
-    private static native int nativeCreate(String name,
-            int cursorWindowSize, boolean localOnly);
+    private static native int nativeCreate(String name, int cursorWindowSize);
     private static native int nativeCreateFromParcel(Parcel parcel);
     private static native void nativeDispose(int windowPtr);
     private static native void nativeWriteToParcel(int windowPtr, Parcel parcel);
@@ -93,14 +92,10 @@
      * </p>
      *
      * @param name The name of the cursor window, or null if none.
-     * @param localWindow True if this window will be used in this process only,
-     * false if it might be sent to another processes.
-     *
-     * @hide
      */
-    public CursorWindow(String name, boolean localWindow) {
+    public CursorWindow(String name) {
         mStartPos = 0;
-        mWindowPtr = nativeCreate(name, sCursorWindowSize, localWindow);
+        mWindowPtr = nativeCreate(name, sCursorWindowSize);
         if (mWindowPtr == 0) {
             throw new CursorWindowAllocationException("Cursor window allocation of " +
                     (sCursorWindowSize / 1024) + " kb failed. " + printStats());
@@ -117,10 +112,14 @@
      * </p>
      *
      * @param localWindow True if this window will be used in this process only,
-     * false if it might be sent to another processes.
+     * false if it might be sent to another processes.  This argument is ignored.
+     *
+     * @deprecated There is no longer a distinction between local and remote
+     * cursor windows.  Use the {@link #CursorWindow(String)} constructor instead.
      */
+    @Deprecated
     public CursorWindow(boolean localWindow) {
-        this(null, localWindow);
+        this((String)null);
     }
 
     private CursorWindow(Parcel source) {
@@ -272,8 +271,7 @@
      * Returns true if the field at the specified row and column index
      * has type {@link Cursor#FIELD_TYPE_NULL}.
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return True if the field has type {@link Cursor#FIELD_TYPE_NULL}.
      * @deprecated Use {@link #getType(int, int)} instead.
@@ -287,8 +285,7 @@
      * Returns true if the field at the specified row and column index
      * has type {@link Cursor#FIELD_TYPE_BLOB} or {@link Cursor#FIELD_TYPE_NULL}.
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return True if the field has type {@link Cursor#FIELD_TYPE_BLOB} or
      * {@link Cursor#FIELD_TYPE_NULL}.
@@ -304,8 +301,7 @@
      * Returns true if the field at the specified row and column index
      * has type {@link Cursor#FIELD_TYPE_INTEGER}.
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return True if the field has type {@link Cursor#FIELD_TYPE_INTEGER}.
      * @deprecated Use {@link #getType(int, int)} instead.
@@ -319,8 +315,7 @@
      * Returns true if the field at the specified row and column index
      * has type {@link Cursor#FIELD_TYPE_FLOAT}.
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return True if the field has type {@link Cursor#FIELD_TYPE_FLOAT}.
      * @deprecated Use {@link #getType(int, int)} instead.
@@ -334,8 +329,7 @@
      * Returns true if the field at the specified row and column index
      * has type {@link Cursor#FIELD_TYPE_STRING} or {@link Cursor#FIELD_TYPE_NULL}.
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return True if the field has type {@link Cursor#FIELD_TYPE_STRING}
      * or {@link Cursor#FIELD_TYPE_NULL}.
@@ -360,8 +354,7 @@
      * </ul>
      * </p>
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return The field type.
      */
@@ -391,8 +384,7 @@
      * </ul>
      * </p>
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return The value of the field as a byte array.
      */
@@ -427,8 +419,7 @@
      * </ul>
      * </p>
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return The value of the field as a string.
      */
@@ -466,8 +457,7 @@
      * </ul>
      * </p>
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @param buffer The {@link CharArrayBuffer} to hold the string.  It is automatically
      * resized if the requested string is larger than the buffer's current capacity.
@@ -502,8 +492,7 @@
      * </ul>
      * </p>
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return The value of the field as a <code>long</code>.
      */
@@ -535,8 +524,7 @@
      * </ul>
      * </p>
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return The value of the field as a <code>double</code>.
      */
@@ -557,8 +545,7 @@
      * result to <code>short</code>.
      * </p>
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return The value of the field as a <code>short</code>.
      */
@@ -574,8 +561,7 @@
      * result to <code>int</code>.
      * </p>
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return The value of the field as an <code>int</code>.
      */
@@ -591,8 +577,7 @@
      * result to <code>float</code>.
      * </p>
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return The value of the field as an <code>float</code>.
      */
@@ -604,8 +589,7 @@
      * Copies a byte array into the field at the specified row and column index.
      *
      * @param value The value to store.
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return True if successful.
      */
@@ -622,8 +606,7 @@
      * Copies a string into the field at the specified row and column index.
      *
      * @param value The value to store.
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return True if successful.
      */
@@ -640,8 +623,7 @@
      * Puts a long integer into the field at the specified row and column index.
      *
      * @param value The value to store.
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return True if successful.
      */
@@ -659,8 +641,7 @@
      * specified row and column index.
      *
      * @param value The value to store.
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return True if successful.
      */
@@ -676,8 +657,7 @@
     /**
      * Puts a null value into the field at the specified row and column index.
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return True if successful.
      */
diff --git a/core/java/android/database/CursorWrapper.java b/core/java/android/database/CursorWrapper.java
index 320733e..7baeb8c 100644
--- a/core/java/android/database/CursorWrapper.java
+++ b/core/java/android/database/CursorWrapper.java
@@ -25,9 +25,13 @@
  * use for this class is to extend a cursor while overriding only a subset of its methods.
  */
 public class CursorWrapper implements Cursor {
+    /** @hide */
+    protected final Cursor mCursor;
 
-    private final Cursor mCursor;
-
+    /**
+     * Creates a cursor wrapper.
+     * @param cursor The underlying cursor to wrap.
+     */
     public CursorWrapper(Cursor cursor) {
         mCursor = cursor;
     }
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 8e6f699..a10ca15 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -237,7 +237,8 @@
             return Cursor.FIELD_TYPE_BLOB;
         } else if (obj instanceof Float || obj instanceof Double) {
             return Cursor.FIELD_TYPE_FLOAT;
-        } else if (obj instanceof Long || obj instanceof Integer) {
+        } else if (obj instanceof Long || obj instanceof Integer
+                || obj instanceof Short || obj instanceof Byte) {
             return Cursor.FIELD_TYPE_INTEGER;
         } else {
             return Cursor.FIELD_TYPE_STRING;
@@ -245,6 +246,82 @@
     }
 
     /**
+     * Fills the specified cursor window by iterating over the contents of the cursor.
+     * The window is filled until the cursor is exhausted or the window runs out
+     * of space.
+     *
+     * The original position of the cursor is left unchanged by this operation.
+     *
+     * @param cursor The cursor that contains the data to put in the window.
+     * @param position The start position for filling the window.
+     * @param window The window to fill.
+     * @hide
+     */
+    public static void cursorFillWindow(final Cursor cursor,
+            int position, final CursorWindow window) {
+        if (position < 0 || position >= cursor.getCount()) {
+            return;
+        }
+        window.acquireReference();
+        try {
+            final int oldPos = cursor.getPosition();
+            final int numColumns = cursor.getColumnCount();
+            window.clear();
+            window.setStartPosition(position);
+            window.setNumColumns(numColumns);
+            if (cursor.moveToPosition(position)) {
+                do {
+                    if (!window.allocRow()) {
+                        break;
+                    }
+                    for (int i = 0; i < numColumns; i++) {
+                        final int type = cursor.getType(i);
+                        final boolean success;
+                        switch (type) {
+                            case Cursor.FIELD_TYPE_NULL:
+                                success = window.putNull(position, i);
+                                break;
+
+                            case Cursor.FIELD_TYPE_INTEGER:
+                                success = window.putLong(cursor.getLong(i), position, i);
+                                break;
+
+                            case Cursor.FIELD_TYPE_FLOAT:
+                                success = window.putDouble(cursor.getDouble(i), position, i);
+                                break;
+
+                            case Cursor.FIELD_TYPE_BLOB: {
+                                final byte[] value = cursor.getBlob(i);
+                                success = value != null ? window.putBlob(value, position, i)
+                                        : window.putNull(position, i);
+                                break;
+                            }
+
+                            default: // assume value is convertible to String
+                            case Cursor.FIELD_TYPE_STRING: {
+                                final String value = cursor.getString(i);
+                                success = value != null ? window.putString(value, position, i)
+                                        : window.putNull(position, i);
+                                break;
+                            }
+                        }
+                        if (!success) {
+                            window.freeLastRow();
+                            break;
+                        }
+                    }
+                    position += 1;
+                } while (cursor.moveToNext());
+            }
+            cursor.moveToPosition(oldPos);
+        } catch (IllegalStateException e){
+            // simply ignore it
+        } finally {
+            window.releaseReference();
+        }
+    }
+
+    /**
      * Appends an SQL string to the given StringBuilder, including the opening
      * and closing single quotes. Any single quotes internal to sqlString will
      * be escaped.
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index a1c36e2..9574300 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -155,7 +155,7 @@
     }
 
     private void fillWindow(int startPos) {
-        clearOrCreateLocalWindow(getDatabase().getPath());
+        clearOrCreateWindow(getDatabase().getPath());
         mWindow.setStartPosition(startPos);
         int count = getQuery().fillWindow(mWindow);
         if (startPos == 0) { // fillWindow returns count(*) only for startPos = 0
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index fe0106d..33310df 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -768,61 +768,6 @@
     }
 
     /**
-     * TODO: Remove this once pre-built apk's (Maps, Youtube etc) are updated
-     * @deprecated use {@link CreateNdefMessageCallback} or {@link OnNdefPushCompleteCallback}
-     * @hide
-     */
-    @Deprecated
-    public interface NdefPushCallback {
-        /**
-         * @deprecated use {@link CreateNdefMessageCallback} instead
-         */
-        @Deprecated
-        NdefMessage createMessage();
-        /**
-         * @deprecated use{@link OnNdefPushCompleteCallback} instead
-         */
-        @Deprecated
-        void onMessagePushed();
-    }
-
-    /**
-     * TODO: Remove this
-     * Converts new callbacks to old callbacks.
-     */
-    static final class LegacyCallbackWrapper implements CreateNdefMessageCallback,
-            OnNdefPushCompleteCallback {
-        final NdefPushCallback mLegacyCallback;
-        LegacyCallbackWrapper(NdefPushCallback legacyCallback) {
-            mLegacyCallback = legacyCallback;
-        }
-        @Override
-        public void onNdefPushComplete(NfcEvent event) {
-            mLegacyCallback.onMessagePushed();
-        }
-        @Override
-        public NdefMessage createNdefMessage(NfcEvent event) {
-            return mLegacyCallback.createMessage();
-        }
-    }
-
-    /**
-     * TODO: Remove this once pre-built apk's (Maps, Youtube etc) are updated
-     * @deprecated use {@link #setNdefPushMessageCallback} instead
-     * @hide
-     */
-    @Deprecated
-    public void enableForegroundNdefPush(Activity activity, final NdefPushCallback callback) {
-        if (activity == null || callback == null) {
-            throw new NullPointerException();
-        }
-        enforceResumed(activity);
-        LegacyCallbackWrapper callbackWrapper = new LegacyCallbackWrapper(callback);
-        mNfcActivityManager.setNdefPushMessageCallback(activity, callbackWrapper);
-        mNfcActivityManager.setOnNdefPushCompleteCallback(activity, callbackWrapper);
-    }
-
-    /**
      * Enable NDEF Push feature.
      * <p>This API is for the Settings application.
      * @hide
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 4d7a9bb..cc2fa85 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -35,7 +35,6 @@
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -902,15 +901,13 @@
             return false;
         }
 
+        // Thread policy controls BlockGuard.
         int threadPolicyMask = StrictMode.DETECT_DISK_WRITE |
                 StrictMode.DETECT_DISK_READ |
                 StrictMode.DETECT_NETWORK;
 
         if (!IS_USER_BUILD) {
             threadPolicyMask |= StrictMode.PENALTY_DROPBOX;
-            if (IS_ENG_BUILD) {
-                threadPolicyMask |= StrictMode.PENALTY_LOG;
-            }
         }
         if (doFlashes) {
             threadPolicyMask |= StrictMode.PENALTY_FLASH;
@@ -918,6 +915,8 @@
 
         StrictMode.setThreadPolicyMask(threadPolicyMask);
 
+        // VM Policy controls CloseGuard, detection of Activity leaks,
+        // and instance counting.
         if (IS_USER_BUILD) {
             setCloseGuardEnabled(false);
         } else {
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 4b4d308..d7060c1 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -300,8 +300,25 @@
         public static final String CALENDAR_COLOR = "calendar_color";
 
         /**
+         * An index for looking up a color from the {@link Colors} table. NULL
+         * or an empty string are reserved for indicating that the calendar does
+         * not use an index for looking up the color. The provider will update
+         * {@link #CALENDAR_COLOR} automatically when a valid index is written
+         * to this column. @see Colors
+         * <P>
+         * Type: TEXT
+         * </P>
+         * TODO UNHIDE
+         *
+         * @hide
+         */
+        public static final String CALENDAR_COLOR_INDEX = "calendar_color_index";
+
+        /**
          * The display name of the calendar. Column name.
-         * <P>Type: TEXT</P>
+         * <P>
+         * Type: TEXT
+         * </P>
          */
         public static final String CALENDAR_DISPLAY_NAME = "calendar_displayName";
 
@@ -392,6 +409,34 @@
          * <P>Type: TEXT</P>
          */
         public static final String ALLOWED_REMINDERS = "allowedReminders";
+
+        /**
+         * A comma separated list of availability types supported for this
+         * calendar in the format "#,#,#". Valid types are
+         * {@link Events#AVAILABILITY_BUSY}, {@link Events#AVAILABILITY_FREE},
+         * {@link Events#AVAILABILITY_TENTATIVE}. Setting this field to only
+         * {@link Events#AVAILABILITY_BUSY} should be used to indicate that
+         * changing the availability is not supported.
+         *
+         * TODO UNHIDE, Update Calendars doc
+         *
+         * @hide
+         */
+        public static final String ALLOWED_AVAILABILITY = "allowedAvailability";
+
+        /**
+         * A comma separated list of attendee types supported for this calendar
+         * in the format "#,#,#". Valid types are {@link Attendees#TYPE_NONE},
+         * {@link Attendees#TYPE_OPTIONAL}, {@link Attendees#TYPE_REQUIRED},
+         * {@link Attendees#TYPE_RESOURCE}. Setting this field to only
+         * {@link Attendees#TYPE_NONE} should be used to indicate that changing
+         * the attendee type is not supported.
+         *
+         * TODO UNHIDE, Update Calendars doc
+         *
+         * @hide
+         */
+        public static final String ALLOWED_ATTENDEE_TYPES = "allowedAttendeeTypes";
     }
 
     /**
@@ -688,13 +733,22 @@
 
         /**
          * The type of attendee. Column name.
-         * <P>Type: Integer (one of {@link #TYPE_REQUIRED}, {@link #TYPE_OPTIONAL})</P>
+         * <P>
+         * Type: Integer (one of {@link #TYPE_REQUIRED}, {@link #TYPE_OPTIONAL}
+         * </P>
          */
         public static final String ATTENDEE_TYPE = "attendeeType";
 
         public static final int TYPE_NONE = 0;
         public static final int TYPE_REQUIRED = 1;
         public static final int TYPE_OPTIONAL = 2;
+        /**
+         * This specifies that an attendee is a resource, such as a room, and
+         * not an actual person. TODO UNHIDE and add to ATTENDEE_TYPE comment
+         * 
+         * @hide
+         */
+        public static final int TYPE_RESOURCE = 3;
 
         /**
          * The attendance status of the attendee. Column name.
@@ -787,13 +841,26 @@
         public static final String EVENT_LOCATION = "eventLocation";
 
         /**
-         * A secondary color for the individual event. Reserved for future use.
-         * Column name.
+         * A secondary color for the individual event. This should only be
+         * updated by the sync adapter for a given account.
          * <P>Type: INTEGER</P>
          */
         public static final String EVENT_COLOR = "eventColor";
 
         /**
+         * A secondary color index for the individual event. NULL or an empty
+         * string are reserved for indicating that the event does not use an
+         * index for looking up the color. The provider will update
+         * {@link #EVENT_COLOR} automatically when a valid index is written to
+         * this column. @see Colors
+         * <P>Type: TEXT</P>
+         * TODO UNHIDE
+         *
+         * @hide
+         */
+        public static final String EVENT_COLOR_INDEX = "eventColor_index";
+
+        /**
          * The event status. Column name.
          * <P>Type: INTEGER (one of {@link #STATUS_TENTATIVE}...)</P>
          */
@@ -964,6 +1031,15 @@
          * other events.
          */
         public static final int AVAILABILITY_FREE = 1;
+        /**
+         * Indicates that the owner's availability may change, but should be
+         * considered busy time that will conflict.
+         *
+         * TODO UNHIDE
+         *
+         * @hide
+         */
+        public static final int AVAILABILITY_TENTATIVE = 2;
 
         /**
          * Whether the event has an alarm or not. Column name.
@@ -2224,6 +2300,91 @@
         }
     }
 
+    /**
+     * @hide
+     * TODO UNHIDE
+     */
+    protected interface ColorsColumns extends SyncStateContract.Columns {
+
+        /**
+         * The type of color, which describes how it should be used. Valid types
+         * are {@link #TYPE_CALENDAR} and {@link #TYPE_EVENT}. Column name.
+         * <P>
+         * Type: INTEGER (NOT NULL)
+         * </P>
+         */
+        public static final String COLOR_TYPE = "color_type";
+
+        /**
+         * This indicateds a color that can be used for calendars.
+         */
+        public static final int TYPE_CALENDAR = 0;
+        /**
+         * This indicates a color that can be used for events.
+         */
+        public static final int TYPE_EVENT = 1;
+
+        /**
+         * The index used to reference this color. This can be any non-empty
+         * string, but must be unique for a given {@link #ACCOUNT_TYPE} and
+         * {@link #ACCOUNT_NAME} . Column name.
+         * <P>
+         * Type: TEXT
+         * </P>
+         */
+        public static final String COLOR_INDEX = "color_index";
+
+        /**
+         * The version of this color that will work with dark text as an 8-bit
+         * ARGB integer value. Colors should specify alpha as fully opaque (eg
+         * 0xFF993322) as the alpha may be ignored or modified for display.
+         * Column name.
+         * <P>
+         * Type: INTEGER (NOT NULL)
+         * </P>
+         */
+        public static final String COLOR_LIGHT = "color_light";
+
+        /**
+         * The version of this color that will work with light text as an 8-bit
+         * ARGB integer value. Colors should specify alpha as fully opaque (eg
+         * 0xFF993322) as the alpha may be ignored or modified for display.
+         * Column name.
+         * <P>
+         * Type: INTEGER (NOT NULL)
+         * </P>
+         */
+        public static final String COLOR_DARK = "color_dark";
+
+    }
+
+    /**
+     * Fields for accessing colors available for a given account. Colors are
+     * referenced by {@link #COLOR_INDEX} which must be unique for a given
+     * account name/type. These values should only be updated by the sync
+     * adapter.
+     * TODO UNHIDE
+     *
+     * @hide
+     */
+    public static final class Colors implements ColorsColumns {
+        /**
+         * @hide
+         */
+        public static final String TABLE_NAME = "Colors";
+        /**
+         * The Uri for querying color information
+         */
+        @SuppressWarnings("hiding")
+        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/colors");
+
+        /**
+         * This utility class cannot be instantiated
+         */
+        private Colors() {
+        }
+    }
+
     protected interface ExtendedPropertiesColumns {
         /**
          * The event the extended property belongs to. Column name.
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index e93039b..4ec4bc4 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -197,16 +197,18 @@
     @Override
     protected boolean leftWord(TextView widget, Spannable buffer) {
         final int selectionEnd = widget.getSelectionEnd();
-        mWordIterator.setCharSequence(buffer, selectionEnd, selectionEnd);
-        return Selection.moveToPreceding(buffer, mWordIterator, isSelecting(buffer));
+        final WordIterator wordIterator = widget.getWordIterator();
+        wordIterator.setCharSequence(buffer, selectionEnd, selectionEnd);
+        return Selection.moveToPreceding(buffer, wordIterator, isSelecting(buffer));
     }
 
     /** {@hide} */
     @Override
     protected boolean rightWord(TextView widget, Spannable buffer) {
         final int selectionEnd = widget.getSelectionEnd();
-        mWordIterator.setCharSequence(buffer, selectionEnd, selectionEnd);
-        return Selection.moveToFollowing(buffer, mWordIterator, isSelecting(buffer));
+        final WordIterator wordIterator = widget.getWordIterator();
+        wordIterator.setCharSequence(buffer, selectionEnd, selectionEnd);
+        return Selection.moveToFollowing(buffer, wordIterator, isSelecting(buffer));
     }
 
     @Override
@@ -322,8 +324,6 @@
         return sInstance;
     }
 
-    private WordIterator mWordIterator = new WordIterator();
-
     private static final Object LAST_TAP_DOWN = new Object();
     private static ArrowKeyMovementMethod sInstance;
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 7eae739..b9e0fe8 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -425,20 +425,17 @@
                     }
                 }
 
+                CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
+                mTranslator = compatibilityInfo.getTranslator();
+
                 // If the application owns the surface, don't enable hardware acceleration
                 if (mSurfaceHolder == null) {
                     enableHardwareAcceleration(attrs);
                 }
 
-                CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
-                mTranslator = compatibilityInfo.getTranslator();
-
-                if (mTranslator != null) {
-                    mSurface.setCompatibilityTranslator(mTranslator);
-                }
-
                 boolean restore = false;
                 if (mTranslator != null) {
+                    mSurface.setCompatibilityTranslator(mTranslator);
                     restore = true;
                     attrs.backup();
                     mTranslator.translateWindowLayout(attrs);
@@ -590,6 +587,9 @@
         mAttachInfo.mHardwareAccelerated = false;
         mAttachInfo.mHardwareAccelerationRequested = false;
 
+        // Don't enable hardware acceleration when the application is in compatibility mode
+        if (mTranslator != null) return;
+
         // Try to enable hardware acceleration if requested
         final boolean hardwareAccelerated = 
                 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index fe06d98..a4e0688 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -391,8 +391,6 @@
      * Gets the max scroll offset of the source left edge in pixels.
      *
      * @return The max scroll.
-     *
-     * @hide
      */
     public int getMaxScrollX() {
         return mMaxScrollX;
@@ -401,8 +399,6 @@
      * Sets the max scroll offset of the source left edge in pixels.
      *
      * @param maxScrollX The max scroll.
-     *
-     * @hide
      */
     public void setMaxScrollX(int maxScrollX) {
         enforceNotSealed();
@@ -413,8 +409,6 @@
      * Gets the max scroll offset of the source top edge in pixels.
      *
      * @return The max scroll.
-     *
-     * @hide
      */
     public int getMaxScrollY() {
         return mMaxScrollY;
@@ -424,8 +418,6 @@
      * Sets the max scroll offset of the source top edge in pixels.
      *
      * @param maxScrollY The max scroll.
-     *
-     * @hide
      */
     public void setMaxScrollY(int maxScrollY) {
         enforceNotSealed();
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index ae40ded..3d129f7 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -95,27 +95,33 @@
     public void onHideCustomView() {}
 
     /**
-     * Request the host application to create a new Webview. The host
-     * application should handle placement of the new WebView in the view
-     * system. The default behavior returns null.
-     * @param view The WebView that initiated the callback.
-     * @param dialog True if the new window is meant to be a small dialog
-     *               window.
-     * @param userGesture True if the request was initiated by a user gesture
-     *                    such as clicking a link.
-     * @param resultMsg The message to send when done creating a new WebView.
-     *                  Set the new WebView through resultMsg.obj which is 
-     *                  WebView.WebViewTransport() and then call
-     *                  resultMsg.sendToTarget();
-     * @return Similar to javscript dialogs, this method should return true if
-     *         the client is going to handle creating a new WebView. Note that
-     *         the WebView will halt processing if this method returns true so
-     *         make sure to call resultMsg.sendToTarget(). It is undefined
-     *         behavior to call resultMsg.sendToTarget() after returning false
-     *         from this method.
+     * Request the host application to create a new window. If the host
+     * application chooses to honor this request, it should return true from
+     * this method, create a new WebView to host the window, insert it into the
+     * View system and send the supplied resultMsg message to its target with
+     * the new WebView as an argument. If the host application chooses not to
+     * honor the request, it should return false from this method. The default
+     * implementation of this method does nothing and hence returns false.
+     * @param view The WebView from which the request for a new window
+     *             originated.
+     * @param isDialog True if the new window should be a dialog, rather than
+     *                 a full-size window.
+     * @param isUserGesture True if the request was initiated by a user gesture,
+     *                      such as the user clicking a link.
+     * @param resultMsg The message to send when once a new WebView has been
+     *                  created. resultMsg.obj is a
+     *                  {@link WebView.WebViewTransport} object. This should be
+     *                  used to transport the new WebView, by calling
+     *                  {@link WebView.WebViewTransport#setWebView(WebView)
+     *                  WebView.WebViewTransport.setWebView(WebView)}.
+     * @return This method should return true if the host application will
+     *         create a new window, in which case resultMsg should be sent to
+     *         its target. Otherwise, this method should return false. Returning
+     *         false from this method but also sending resultMsg will result in
+     *         undefined behavior.
      */
-    public boolean onCreateWindow(WebView view, boolean dialog,
-            boolean userGesture, Message resultMsg) {
+    public boolean onCreateWindow(WebView view, boolean isDialog,
+            boolean isUserGesture, Message resultMsg) {
         return false;
     }
 
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 48615bd..cf6e187 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2003,15 +2003,18 @@
     }
 
     /**
-     * Load the given url with the extra headers.
-     * @param url The url of the resource to load.
-     * @param extraHeaders The extra headers sent with this url. This should not
-     *            include the common headers like "user-agent". If it does, it
-     *            will be replaced by the intrinsic value of the WebView.
+     * Load the given URL with the specified additional HTTP headers.
+     * @param url The URL of the resource to load.
+     * @param additionalHttpHeaders The additional headers to be used in the
+     *            HTTP request for this URL, specified as a map from name to
+     *            value. Note that if this map contains any of the headers
+     *            that are set by default by the WebView, such as those
+     *            controlling caching, accept types or the User-Agent, their
+     *            values may be overriden by the WebView's defaults.
      */
-    public void loadUrl(String url, Map<String, String> extraHeaders) {
+    public void loadUrl(String url, Map<String, String> additionalHttpHeaders) {
         checkThread();
-        loadUrlImpl(url, extraHeaders);
+        loadUrlImpl(url, additionalHttpHeaders);
     }
 
     private void loadUrlImpl(String url, Map<String, String> extraHeaders) {
@@ -2024,8 +2027,8 @@
     }
 
     /**
-     * Load the given url.
-     * @param url The url of the resource to load.
+     * Load the given URL.
+     * @param url The URL of the resource to load.
      */
     public void loadUrl(String url) {
         checkThread();
@@ -4501,6 +4504,9 @@
             if (mHeldMotionless == MOTIONLESS_FALSE) {
                 mPrivateHandler.sendMessageDelayed(mPrivateHandler
                         .obtainMessage(DRAG_HELD_MOTIONLESS), MOTIONLESS_TIME);
+                mPrivateHandler.sendMessageDelayed(mPrivateHandler
+                        .obtainMessage(AWAKEN_SCROLL_BARS),
+                            ViewConfiguration.getScrollDefaultDelay());
                 mHeldMotionless = MOTIONLESS_PENDING;
             }
         }
@@ -5998,6 +6004,7 @@
                     mTouchMode = TOUCH_DRAG_START_MODE;
                     mConfirmMove = true;
                     mPrivateHandler.removeMessages(RESUME_WEBCORE_PRIORITY);
+                    nativeSetIsScrolling(false);
                 } else if (mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) {
                     mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
                     if (USE_WEBKIT_RINGS || getSettings().supportTouchOnly()) {
@@ -6280,9 +6287,16 @@
                     }
                     mLastTouchX = x;
                     mLastTouchY = y;
-                    if ((deltaX | deltaY) != 0) {
+
+                    if (deltaX * deltaX + deltaY * deltaY > mTouchSlopSquare) {
                         mHeldMotionless = MOTIONLESS_FALSE;
+                        nativeSetIsScrolling(true);
+                    } else {
+                        mHeldMotionless = MOTIONLESS_TRUE;
+                        nativeSetIsScrolling(false);
+                        keepScrollBarsVisible = true;
                     }
+
                     mLastTouchTime = eventTime;
                 }
 
@@ -6298,9 +6312,15 @@
                     // keep the scrollbar on the screen even there is no scroll
                     awakenScrollBars(ViewConfiguration.getScrollDefaultDelay(),
                             false);
+                    // Post a message so that we'll keep them alive while we're not scrolling.
+                    mPrivateHandler.sendMessageDelayed(mPrivateHandler
+                            .obtainMessage(AWAKEN_SCROLL_BARS),
+                            ViewConfiguration.getScrollDefaultDelay());
                     // return false to indicate that we can't pan out of the
                     // view space
                     return !done;
+                } else {
+                    mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
                 }
                 break;
             }
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 510e2d4..5fbbe4d 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -32,6 +32,7 @@
 import com.android.internal.util.ArrayUtils;
 
 import java.text.BreakIterator;
+import java.util.Locale;
 
 
 /**
@@ -45,7 +46,7 @@
 
     private final TextView mTextView;
 
-    final SpellCheckerSession mSpellCheckerSession;
+    SpellCheckerSession mSpellCheckerSession;
     final int mCookie;
 
     // Paired arrays for the (id, spellCheckSpan) pair. A negative id means the associated
@@ -61,23 +62,54 @@
 
     private int mSpanSequenceCounter = 0;
 
+    private Locale mCurrentLocale;
+
+    // Shared by all SpellParsers. Cannot be shared with TextView since it may be used
+    // concurrently due to the asynchronous nature of onGetSuggestions.
+    private WordIterator mWordIterator;
+
     public SpellChecker(TextView textView) {
         mTextView = textView;
 
-        final TextServicesManager textServicesManager = (TextServicesManager) textView.getContext().
-                getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
-        mSpellCheckerSession = textServicesManager.newSpellCheckerSession(
-                null /* not currently used by the textServicesManager */,
-                null /* null locale means use the languages defined in Settings
-                        if referToSpellCheckerLanguageSettings is true */,
-                        this, true /* means use the languages defined in Settings */);
-        mCookie = hashCode();
-
-        // Arbitrary: 4 simultaneous spell check spans. Will automatically double size on demand
+        // Arbitrary: these arrays will automatically double their sizes on demand
         final int size = ArrayUtils.idealObjectArraySize(1);
         mIds = new int[size];
         mSpellCheckSpans = new SpellCheckSpan[size];
+
+        setLocale(mTextView.getLocale());
+
+        mCookie = hashCode();
+    }
+
+    private void setLocale(Locale locale) {
+        final TextServicesManager textServicesManager = (TextServicesManager)
+                mTextView.getContext().getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
+        mSpellCheckerSession = textServicesManager.newSpellCheckerSession(
+                null /* Bundle not currently used by the textServicesManager */,
+                locale, this, false /* means any available languages from current spell checker */);
+        mCurrentLocale = locale;
+
+        // Restore SpellCheckSpans in pool
+        for (int i = 0; i < mLength; i++) {
+            mSpellCheckSpans[i].setSpellCheckInProgress(false);
+            mIds[i] = -1;
+        }
         mLength = 0;
+
+        // Change SpellParsers' wordIterator locale
+        mWordIterator = new WordIterator(locale);
+
+        // Stop all SpellParsers
+        final int length = mSpellParsers.length;
+        for (int i = 0; i < length; i++) {
+            mSpellParsers[i].finish();
+        }
+
+        // Remove existing misspelled SuggestionSpans
+        mTextView.removeMisspelledSpans((Editable) mTextView.getText());
+
+        // This class is the listener for locale change: warn other locale-aware objects
+        mTextView.onLocaleChanged();
     }
 
     /**
@@ -95,7 +127,7 @@
 
         final int length = mSpellParsers.length;
         for (int i = 0; i < length; i++) {
-            mSpellParsers[i].close();
+            mSpellParsers[i].finish();
         }
     }
 
@@ -140,12 +172,20 @@
     }
 
     public void spellCheck(int start, int end) {
+        final Locale locale = mTextView.getLocale();
+        if (mCurrentLocale == null || (!(mCurrentLocale.equals(locale)))) {
+            setLocale(locale);
+            // Re-check the entire text
+            start = 0;
+            end = mTextView.getText().length();
+        }
+
         if (!isSessionActive()) return;
 
         final int length = mSpellParsers.length;
         for (int i = 0; i < length; i++) {
             final SpellParser spellParser = mSpellParsers[i];
-            if (spellParser.isDone()) {
+            if (spellParser.isFinished()) {
                 spellParser.init(start, end);
                 spellParser.parse();
                 return;
@@ -229,7 +269,7 @@
         final int length = mSpellParsers.length;
         for (int i = 0; i < length; i++) {
             final SpellParser spellParser = mSpellParsers[i];
-            if (!spellParser.isDone()) {
+            if (!spellParser.isFinished()) {
                 spellParser.parse();
             }
         }
@@ -239,6 +279,7 @@
             SuggestionsInfo suggestionsInfo, SpellCheckSpan spellCheckSpan) {
         final int start = editable.getSpanStart(spellCheckSpan);
         final int end = editable.getSpanEnd(spellCheckSpan);
+        if (start < 0 || end < 0) return; // span was removed in the meantime
 
         // Other suggestion spans may exist on that region, with identical suggestions, filter
         // them out to avoid duplicates. First, filter suggestion spans on that exact region.
@@ -249,7 +290,6 @@
             final int spanEnd = editable.getSpanEnd(suggestionSpans[i]);
             if (spanStart != start || spanEnd != end) {
                 suggestionSpans[i] = null;
-                break;
             }
         }
 
@@ -301,7 +341,6 @@
     }
 
     private class SpellParser {
-        private WordIterator mWordIterator = new WordIterator(/*TODO Locale*/);
         private Object mRange = new Object();
 
         public void init(int start, int end) {
@@ -309,11 +348,11 @@
                     Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
         }
 
-        public void close() {
+        public void finish() {
             ((Editable) mTextView.getText()).removeSpan(mRange);
         }
 
-        public boolean isDone() {
+        public boolean isFinished() {
             return ((Editable) mTextView.getText()).getSpanStart(mRange) < 0;
         }
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a21a087..55e49ea 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -132,6 +132,7 @@
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethodSubtype;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.RemoteViews.RemoteView;
 
@@ -147,6 +148,7 @@
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.Locale;
 
 /**
  * Displays text to the user and optionally allows them to edit it.  A TextView
@@ -357,6 +359,8 @@
 
     private SpellChecker mSpellChecker;
 
+    private boolean mShowSoftInputOnFocus = true;
+
     // The alignment to pass to Layout, or null if not resolved.
     private Layout.Alignment mLayoutAlignment;
 
@@ -605,6 +609,12 @@
                 mLinksClickable = a.getBoolean(attr, true);
                 break;
 
+//            TODO uncomment when this attribute is made public in the next release
+//                 also add TextView_showSoftInputOnFocus to the list of attributes above
+//            case com.android.internal.R.styleable.TextView_showSoftInputOnFocus:
+//                setShowSoftInputOnFocus(a.getBoolean(attr, true));
+//                break;
+
             case com.android.internal.R.styleable.TextView_drawableLeft:
                 drawableLeft = a.getDrawable(attr);
                 break;
@@ -2368,6 +2378,29 @@
     }
 
     /**
+     * Sets whether the soft input method will be made visible when this
+     * TextView gets focused. The default is true.
+     *
+     * @attr ref android.R.styleable#TextView_showSoftInputOnFocus
+     * @hide
+     */
+    @android.view.RemotableViewMethod
+    public final void setShowSoftInputOnFocus(boolean show) {
+        mShowSoftInputOnFocus = show;
+    }
+
+    /**
+     * Returns whether the soft input method will be made visible when this
+     * TextView gets focused. The default is true.
+     *
+     * @attr ref android.R.styleable#TextView_showSoftInputOnFocus
+     * @hide
+     */
+    public final boolean getShowSoftInputOnFocus() {
+        return mShowSoftInputOnFocus;
+    }
+
+    /**
      * Returns the list of URLSpans attached to the text
      * (by {@link Linkify} or otherwise) if any.  You can call
      * {@link URLSpan#getURL} on them to find where they link to
@@ -2942,15 +2975,7 @@
                     sp.removeSpan(cw);
                 }
 
-                SuggestionSpan[] suggestionSpans = sp.getSpans(0, sp.length(), SuggestionSpan.class);
-                for (int i = 0; i < suggestionSpans.length; i++) {
-                    int flags = suggestionSpans[i].getFlags();
-                    if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0
-                            && (flags & SuggestionSpan.FLAG_MISSPELLED) != 0) {
-                        sp.removeSpan(suggestionSpans[i]);
-                    }
-                }
-
+                removeMisspelledSpans(sp);
                 sp.removeSpan(mSuggestionRangeSpan);
 
                 ss.text = sp;
@@ -2970,6 +2995,18 @@
         return superState;
     }
 
+    void removeMisspelledSpans(Spannable spannable) {
+        SuggestionSpan[] suggestionSpans = spannable.getSpans(0, spannable.length(),
+                SuggestionSpan.class);
+        for (int i = 0; i < suggestionSpans.length; i++) {
+            int flags = suggestionSpans[i].getFlags();
+            if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0
+                    && (flags & SuggestionSpan.FLAG_MISSPELLED) != 0) {
+                spannable.removeSpan(suggestionSpans[i]);
+            }
+        }
+    }
+
     @Override
     public void onRestoreInstanceState(Parcelable state) {
         if (!(state instanceof SavedState)) {
@@ -5465,7 +5502,7 @@
                                 && mLayout != null && onCheckIsTextEditor()) {
                             InputMethodManager imm = InputMethodManager.peekInstance();
                             viewClicked(imm);
-                            if (imm != null) {
+                            if (imm != null && mShowSoftInputOnFocus) {
                                 imm.showSoftInput(this, 0);
                             }
                         }
@@ -8207,6 +8244,9 @@
             }
 
             hideControllers();
+            if (mSuggestionsPopupWindow != null) {
+                mSuggestionsPopupWindow.onParentLostFocus();
+            }
         }
 
         startStopMarquee(hasWindowFocus);
@@ -8304,7 +8344,7 @@
                 // Show the IME, except when selecting in read-only text.
                 final InputMethodManager imm = InputMethodManager.peekInstance();
                 viewClicked(imm);
-                if (!mTextIsSelectable) {
+                if (!mTextIsSelectable && mShowSoftInputOnFocus) {
                     handled |= imm != null && imm.showSoftInput(this, 0);
                 }
 
@@ -8840,15 +8880,13 @@
             selectionStart = ((Spanned) mText).getSpanStart(urlSpan);
             selectionEnd = ((Spanned) mText).getSpanEnd(urlSpan);
         } else {
-            if (mWordIterator == null) {
-                mWordIterator = new WordIterator();
-            }
-            mWordIterator.setCharSequence(mText, minOffset, maxOffset);
+            final WordIterator wordIterator = getWordIterator();
+            wordIterator.setCharSequence(mText, minOffset, maxOffset);
 
-            selectionStart = mWordIterator.getBeginning(minOffset);
+            selectionStart = wordIterator.getBeginning(minOffset);
             if (selectionStart == BreakIterator.DONE) return false;
 
-            selectionEnd = mWordIterator.getEnd(maxOffset);
+            selectionEnd = wordIterator.getEnd(maxOffset);
             if (selectionEnd == BreakIterator.DONE) return false;
 
             if (selectionStart == selectionEnd) {
@@ -8863,6 +8901,43 @@
         return selectionEnd > selectionStart;
     }
 
+    /**
+     * This is a temporary method. Future versions may support multi-locale text.
+     *
+     * @return The current locale used in this TextView, based on the current IME's locale,
+     * or the system default locale if this is not defined.
+     * @hide
+     */
+    public Locale getLocale() {
+        Locale locale = Locale.getDefault();
+        final InputMethodManager imm = InputMethodManager.peekInstance();
+        if (imm != null) {
+            final InputMethodSubtype currentInputMethodSubtype = imm.getCurrentInputMethodSubtype();
+            if (currentInputMethodSubtype != null) {
+                String localeString = currentInputMethodSubtype.getLocale();
+                if (!TextUtils.isEmpty(localeString)) {
+                    locale = new Locale(localeString);
+                }
+            }
+        }
+        return locale;
+    }
+
+    void onLocaleChanged() {
+        // Will be re-created on demand in getWordIterator with the proper new locale
+        mWordIterator = null;
+    }
+
+    /**
+     * @hide
+     */
+    public WordIterator getWordIterator() {
+        if (mWordIterator == null) {
+            mWordIterator = new WordIterator(getLocale());
+        }
+        return mWordIterator;
+    }
+
     private long getCharRange(int offset) {
         final int textLength = mText.length();
         if (offset + 1 < textLength) {
@@ -9547,6 +9622,7 @@
         private SuggestionInfo[] mSuggestionInfos;
         private int mNumberOfSuggestions;
         private boolean mCursorWasVisibleBeforeSuggestions;
+        private boolean mIsShowingUp = false;
         private SuggestionAdapter mSuggestionsAdapter;
         private final Comparator<SuggestionSpan> mSuggestionSpanComparator;
         private final HashMap<SuggestionSpan, Integer> mSpansLengths;
@@ -9602,6 +9678,14 @@
             }
         }
 
+        public boolean isShowingUp() {
+            return mIsShowingUp;
+        }
+
+        public void onParentLostFocus() {
+            mIsShowingUp = false;
+        }
+
         private class SuggestionInfo {
             int suggestionStart, suggestionEnd; // range of actual suggestion within text
             SuggestionSpan suggestionSpan; // the SuggestionSpan that this TextView represents
@@ -9609,15 +9693,6 @@
             SpannableStringBuilder text = new SpannableStringBuilder();
             TextAppearanceSpan highlightSpan = new TextAppearanceSpan(mContext,
                     android.R.style.TextAppearance_SuggestionHighlight);
-
-            void removeMisspelledFlag() {
-                int suggestionSpanFlags = suggestionSpan.getFlags();
-                if ((suggestionSpanFlags & SuggestionSpan.FLAG_MISSPELLED) > 0) {
-                    suggestionSpanFlags &= ~SuggestionSpan.FLAG_MISSPELLED;
-                    suggestionSpanFlags &= ~SuggestionSpan.FLAG_EASY_CORRECT;
-                    suggestionSpan.setFlags(suggestionSpanFlags);
-                }
-            }
         }
 
         private class SuggestionAdapter extends BaseAdapter {
@@ -9714,6 +9789,7 @@
             updateSuggestions();
             mCursorWasVisibleBeforeSuggestions = mCursorVisible;
             setCursorVisible(false);
+            mIsShowingUp = true;
             super.show();
         }
 
@@ -9891,14 +9967,16 @@
             if (suggestionInfo.suggestionIndex == DELETE_TEXT) {
                 final int spanUnionStart = editable.getSpanStart(mSuggestionRangeSpan);
                 int spanUnionEnd = editable.getSpanEnd(mSuggestionRangeSpan);
-                // Do not leave two adjacent spaces after deletion, or one at beginning of text
-                if (spanUnionEnd < editable.length() &&
-                        Character.isSpaceChar(editable.charAt(spanUnionEnd)) &&
-                        (spanUnionStart == 0 ||
-                        Character.isSpaceChar(editable.charAt(spanUnionStart - 1)))) {
+                if (spanUnionStart >= 0 && spanUnionEnd > spanUnionStart) {
+                    // Do not leave two adjacent spaces after deletion, or one at beginning of text
+                    if (spanUnionEnd < editable.length() &&
+                            Character.isSpaceChar(editable.charAt(spanUnionEnd)) &&
+                            (spanUnionStart == 0 ||
+                            Character.isSpaceChar(editable.charAt(spanUnionStart - 1)))) {
                         spanUnionEnd = spanUnionEnd + 1;
+                    }
+                    editable.replace(spanUnionStart, spanUnionEnd, "");
                 }
-                editable.replace(spanUnionStart, spanUnionEnd, "");
                 hide();
                 return;
             }
@@ -9933,6 +10011,14 @@
                     suggestionSpansStarts[i] = editable.getSpanStart(suggestionSpan);
                     suggestionSpansEnds[i] = editable.getSpanEnd(suggestionSpan);
                     suggestionSpansFlags[i] = editable.getSpanFlags(suggestionSpan);
+
+                    // Remove potential misspelled flags
+                    int suggestionSpanFlags = suggestionSpan.getFlags();
+                    if ((suggestionSpanFlags & SuggestionSpan.FLAG_MISSPELLED) > 0) {
+                        suggestionSpanFlags &= ~SuggestionSpan.FLAG_MISSPELLED;
+                        suggestionSpanFlags &= ~SuggestionSpan.FLAG_EASY_CORRECT;
+                        suggestionSpan.setFlags(suggestionSpanFlags);
+                    }
                 }
 
                 final int suggestionStart = suggestionInfo.suggestionStart;
@@ -9941,8 +10027,6 @@
                         suggestionStart, suggestionEnd).toString();
                 editable.replace(spanStart, spanEnd, suggestion);
 
-                suggestionInfo.removeMisspelledFlag();
-
                 // Notify source IME of the suggestion pick. Do this before swaping texts.
                 if (!TextUtils.isEmpty(
                         suggestionInfo.suggestionSpan.getNotificationTargetClassName())) {
@@ -10118,7 +10202,7 @@
         final boolean selectionStarted = mSelectionActionMode != null ||
                 extractedTextModeWillBeStartedFullScreen;
 
-        if (selectionStarted && !mTextIsSelectable && imm != null) {
+        if (selectionStarted && !mTextIsSelectable && imm != null && mShowSoftInputOnFocus) {
             // Show the IME to be able to replace text, except when selecting non editable text.
             imm.showSoftInput(this, 0, null);
         }
@@ -11118,6 +11202,10 @@
     }
 
     private void hideCursorControllers() {
+        if (mSuggestionsPopupWindow != null && !mSuggestionsPopupWindow.isShowingUp()) {
+            // Should be done before hide insertion point controller since it triggers a show of it
+            mSuggestionsPopupWindow.hide();
+        }
         hideInsertionPointCursorController();
         stopSelectionActionMode();
     }
diff --git a/core/java/com/android/internal/view/menu/ExpandedMenuView.java b/core/java/com/android/internal/view/menu/ExpandedMenuView.java
index 723ece4..47058ad 100644
--- a/core/java/com/android/internal/view/menu/ExpandedMenuView.java
+++ b/core/java/com/android/internal/view/menu/ExpandedMenuView.java
@@ -63,11 +63,6 @@
         setChildrenDrawingCacheEnabled(false);
     }
 
-    @Override
-    protected boolean recycleOnMeasure() {
-        return false;
-    }
-
     public boolean invokeItem(MenuItemImpl item) {
         return mMenu.performItemAction(item, 0);
     }
diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java
index a1e16d4..df579c6 100644
--- a/core/java/com/android/internal/view/menu/ListMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java
@@ -34,6 +34,7 @@
  * The item view for each item in the ListView-based MenuViews.
  */
 public class ListMenuItemView extends LinearLayout implements MenuView.ItemView {
+    private static final String TAG = "ListMenuItemView";
     private MenuItemImpl mItemData; 
     
     private ImageView mIconView;
@@ -121,27 +122,25 @@
     }
 
     public void setCheckable(boolean checkable) {
-        
         if (!checkable && mRadioButton == null && mCheckBox == null) {
             return;
         }
         
-        if (mRadioButton == null) {
-            insertRadioButton();
-        }
-        if (mCheckBox == null) {
-            insertCheckBox();
-        }
-        
         // Depending on whether its exclusive check or not, the checkbox or
         // radio button will be the one in use (and the other will be otherCompoundButton)
         final CompoundButton compoundButton;
         final CompoundButton otherCompoundButton; 
 
         if (mItemData.isExclusiveCheckable()) {
+            if (mRadioButton == null) {
+                insertRadioButton();
+            }
             compoundButton = mRadioButton;
             otherCompoundButton = mCheckBox;
         } else {
+            if (mCheckBox == null) {
+                insertCheckBox();
+            }
             compoundButton = mCheckBox;
             otherCompoundButton = mRadioButton;
         }
@@ -155,12 +154,12 @@
             }
             
             // Make sure the other compound button isn't visible
-            if (otherCompoundButton.getVisibility() != GONE) {
+            if (otherCompoundButton != null && otherCompoundButton.getVisibility() != GONE) {
                 otherCompoundButton.setVisibility(GONE);
             }
         } else {
-            mCheckBox.setVisibility(GONE);
-            mRadioButton.setVisibility(GONE);
+            if (mCheckBox != null) mCheckBox.setVisibility(GONE);
+            if (mRadioButton != null) mRadioButton.setVisibility(GONE);
         }
     }
     
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index 722aeea..4a9fcf2 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -57,8 +57,7 @@
     jniThrowException(env, "java/lang/IllegalStateException", msg.string());
 }
 
-static jint nativeCreate(JNIEnv* env, jclass clazz,
-        jstring nameObj, jint cursorWindowSize, jboolean localOnly) {
+static jint nativeCreate(JNIEnv* env, jclass clazz, jstring nameObj, jint cursorWindowSize) {
     String8 name;
     if (nameObj) {
         const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
@@ -70,7 +69,7 @@
     }
 
     CursorWindow* window;
-    status_t status = CursorWindow::create(name, cursorWindowSize, localOnly, &window);
+    status_t status = CursorWindow::create(name, cursorWindowSize, &window);
     if (status || !window) {
         LOGE("Could not allocate CursorWindow '%s' of size %d due to error %d.",
                 name.string(), cursorWindowSize, status);
@@ -477,7 +476,7 @@
 static JNINativeMethod sMethods[] =
 {
     /* name, signature, funcPtr */
-    { "nativeCreate", "(Ljava/lang/String;IZ)I",
+    { "nativeCreate", "(Ljava/lang/String;I)I",
             (void*)nativeCreate },
     { "nativeCreateFromParcel", "(Landroid/os/Parcel;)I",
             (void*)nativeCreateFromParcel },
diff --git a/core/tests/coretests/src/android/database/CursorWindowTest.java b/core/tests/coretests/src/android/database/CursorWindowTest.java
index 07e75cb..8c8081c 100644
--- a/core/tests/coretests/src/android/database/CursorWindowTest.java
+++ b/core/tests/coretests/src/android/database/CursorWindowTest.java
@@ -16,17 +16,11 @@
 
 package android.database;
 
-import android.database.AbstractCursor;
 import android.test.suitebuilder.annotation.SmallTest;
-import com.android.common.ArrayListCursor;
 import android.database.CursorWindow;
 import android.test.PerformanceTestCase;
 
-import com.google.android.collect.Lists;
-
-import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Random;
 
 import junit.framework.TestCase;
 
@@ -41,48 +35,6 @@
     }
 
     @SmallTest
-    public void testWriteCursorToWindow() throws Exception {
-        // create cursor
-        String[] colNames = new String[]{"name", "number", "profit"};
-        int colsize = colNames.length;
-        ArrayList<ArrayList> list = createTestList(10, colsize);
-        AbstractCursor cursor = new ArrayListCursor(colNames, (ArrayList<ArrayList>) list);
-
-        // fill window
-        CursorWindow window = new CursorWindow(false);
-        cursor.fillWindow(0, window);
-
-        // read from cursor window
-        for (int i = 0; i < list.size(); i++) {
-            ArrayList<Integer> col = list.get(i);
-            for (int j = 0; j < colsize; j++) {
-                String s = window.getString(i, j);
-                int r2 = col.get(j);
-                int r1 = Integer.parseInt(s);
-                assertEquals(r2, r1);
-            }
-        }
-
-        // test cursor window handle startpos != 0 
-        window.clear();
-        cursor.fillWindow(1, window);
-        // read from cursor from window
-        for (int i = 1; i < list.size(); i++) {
-            ArrayList<Integer> col = list.get(i);
-            for (int j = 0; j < colsize; j++) {
-                String s = window.getString(i, j);
-                int r2 = col.get(j);
-                int r1 = Integer.parseInt(s);
-                assertEquals(r2, r1);
-            }
-        }
-
-        // Clear the window and make sure it's empty
-        window.clear();
-        assertEquals(0, window.getNumRows());
-    }
-
-    @SmallTest
     public void testValuesLocalWindow() {
         doTestValues(new CursorWindow(true));
     }
@@ -124,50 +76,4 @@
         assertTrue(window.putBlob(blob, 0, 6));
         assertTrue(Arrays.equals(blob, window.getBlob(0, 6)));
     }
-
-    @SmallTest
-    public void testNull() {
-        CursorWindow window = getOneByOneWindow();
-
-        // Put in a null value and read it back as various types
-        assertTrue(window.putNull(0, 0));
-        assertNull(window.getString(0, 0));
-        assertEquals(0, window.getLong(0, 0));
-        assertEquals(0.0, window.getDouble(0, 0));
-        assertNull(window.getBlob(0, 0));
-    }
-
-    @SmallTest
-    public void testEmptyString() {
-        CursorWindow window = getOneByOneWindow();
-
-        // put size 0 string and read it back as various types
-        assertTrue(window.putString("", 0, 0));
-        assertEquals("", window.getString(0, 0));
-        assertEquals(0, window.getLong(0, 0));
-        assertEquals(0.0, window.getDouble(0, 0));
-    }
-
-    private CursorWindow getOneByOneWindow() {
-        CursorWindow window = new CursorWindow(false);
-        assertTrue(window.setNumColumns(1));
-        assertTrue(window.allocRow());
-        return window;
-    }
-    
-    private static ArrayList<ArrayList> createTestList(int rows, int cols) {
-        ArrayList<ArrayList> list = Lists.newArrayList();
-        Random generator = new Random();
-
-        for (int i = 0; i < rows; i++) {
-            ArrayList<Integer> col = Lists.newArrayList();
-            list.add(col);
-            for (int j = 0; j < cols; j++) {
-                // generate random number
-                Integer r = generator.nextInt();
-                col.add(r);
-            }
-        }
-        return list;
-    }
 }
diff --git a/core/tests/coretests/src/android/webkit/AccessibilityInjectorTest.java b/core/tests/coretests/src/android/webkit/AccessibilityInjectorTest.java
index 2ed7c52..417a85f 100644
--- a/core/tests/coretests/src/android/webkit/AccessibilityInjectorTest.java
+++ b/core/tests/coretests/src/android/webkit/AccessibilityInjectorTest.java
@@ -1677,7 +1677,7 @@
                         }
                     });
                 }
-                mWebView.loadData(html, "text/html", "utf-8");
+                mWebView.loadData(html, "text/html", null);
             }
         });
         synchronized (sTestLock) {
diff --git a/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java b/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java
index 7726f02..62466f1 100644
--- a/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java
+++ b/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java
@@ -16,11 +16,11 @@
 
 package android.widget;
 
-import com.android.common.ArrayListCursor;
 import com.google.android.collect.Lists;
 
 import android.content.Context;
 import android.database.Cursor;
+import android.database.MatrixCursor;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -52,14 +52,14 @@
         super.setUp();
         
         // all the pieces needed for the various tests
-        mFrom = new String[]{"Column1", "Column2"};
+        mFrom = new String[]{"Column1", "Column2", "_id"};
         mTo = new int[]{com.android.internal.R.id.text1, com.android.internal.R.id.text2};
         mLayout = com.android.internal.R.layout.simple_list_item_2;
         mContext = getContext();
 
         // raw data for building a basic test cursor
         mData2x2 = createTestList(2, 2);
-        mCursor2x2 = new ArrayListCursor(mFrom, mData2x2);
+        mCursor2x2 = createCursor(mFrom, mData2x2);
     }
     
     /**
@@ -77,6 +77,7 @@
                 Integer r = generator.nextInt();
                 col.add(r);
             }
+            col.add(i);
         }
         return list;
     }
@@ -115,7 +116,7 @@
         
         // now put in a different cursor (5 rows)
         ArrayList<ArrayList> data2 = createTestList(5, 2);
-        Cursor c2 = new ArrayListCursor(mFrom, data2);
+        Cursor c2 = createCursor(mFrom, data2);
         ca.changeCursor(c2);
         
         // Now see if we can pull 5 rows from the adapter
@@ -155,8 +156,8 @@
         assertEquals(columns[1], 1);
 
         // Now make a new cursor with similar data but rearrange the columns
-        String[] swappedFrom = new String[]{"Column2", "Column1"};
-        Cursor c2 = new ArrayListCursor(swappedFrom, mData2x2);
+        String[] swappedFrom = new String[]{"Column2", "Column1", "_id"};
+        Cursor c2 = createCursor(swappedFrom, mData2x2);
         ca.changeCursor(c2);
         assertEquals(2, ca.getCount());
 
@@ -235,7 +236,15 @@
         assertEquals(1, viewIds.length);
         assertEquals(com.android.internal.R.id.text2, viewIds[0]);
     }
-    
+
+    private static MatrixCursor createCursor(String[] columns, ArrayList<ArrayList> list) {
+        MatrixCursor cursor = new MatrixCursor(columns, list.size());
+        for (ArrayList row : list) {
+            cursor.addRow(row);
+        }
+        return cursor;
+    }
+
     /**
      * This is simply a way to sneak a look at the protected mFrom() array.  A more API-
      * friendly way to do this would be to mock out a View and a ViewBinder and exercise
diff --git a/core/tests/coretests/src/android/widget/focus/ListWithMailMessages.java b/core/tests/coretests/src/android/widget/focus/ListWithMailMessages.java
index 5de4ad5..5c891f9 100644
--- a/core/tests/coretests/src/android/widget/focus/ListWithMailMessages.java
+++ b/core/tests/coretests/src/android/widget/focus/ListWithMailMessages.java
@@ -120,7 +120,6 @@
         }
 
         final String mimeType = "text/html";
-        final String encoding = "utf-8";
 
 
         @Override
@@ -137,7 +136,7 @@
             subject.setText(message.getSubject());
 
             WebView body = (WebView) messageUi.findViewById(R.id.body);
-            body.loadData(message.getBody(), mimeType, encoding);
+            body.loadData(message.getBody(), mimeType, null);
 //            body.setText(message.getBody());
             body.setFocusable(message.isFocusable());
 
diff --git a/data/keyboards/keyboards.mk b/data/keyboards/keyboards.mk
index 564f41c..c964961 100644
--- a/data/keyboards/keyboards.mk
+++ b/data/keyboards/keyboards.mk
@@ -24,6 +24,3 @@
 
 PRODUCT_COPY_FILES += $(foreach file,$(keyconfigs),\
     frameworks/base/data/keyboards/$(file):system/usr/idc/$(file))
-
-PRODUCT_PACKAGES := $(keylayouts) $(keycharmaps) $(keyconfigs)
-
diff --git a/docs/html/guide/topics/fundamentals/fragments.jd b/docs/html/guide/topics/fundamentals/fragments.jd
index 8f61945..d34a798 100644
--- a/docs/html/guide/topics/fundamentals/fragments.jd
+++ b/docs/html/guide/topics/fundamentals/fragments.jd
@@ -117,7 +117,7 @@
 two
 fragments in <em>Activity A</em>, when running on an extra large screen (a tablet, for example).
 However, on a normal-sized screen (a phone, for example),
-there's not be enough room for both fragments, so <em>Activity A</em> includes only the fragment for
+there would not be enough room for both fragments, so <em>Activity A</em> includes only the fragment for
 the list of articles, and when the user selects an article, it starts <em>Activity B</em>, which
 includes the fragment to read the article. Thus, the application supports both design patterns
 suggested in figure 1.</p>
diff --git a/include/binder/CursorWindow.h b/include/binder/CursorWindow.h
index 5d490ed..f0284de 100644
--- a/include/binder/CursorWindow.h
+++ b/include/binder/CursorWindow.h
@@ -80,8 +80,7 @@
 
     ~CursorWindow();
 
-    static status_t create(const String8& name, size_t size, bool localOnly,
-            CursorWindow** outCursorWindow);
+    static status_t create(const String8& name, size_t size, CursorWindow** outCursorWindow);
     static status_t createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow);
 
     status_t writeToParcel(Parcel* parcel);
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 3e48459..2eb259e 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -31,7 +31,9 @@
 
 extern const char *MEDIA_MIMETYPE_AUDIO_AMR_NB;
 extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB;
-extern const char *MEDIA_MIMETYPE_AUDIO_MPEG;
+extern const char *MEDIA_MIMETYPE_AUDIO_MPEG;           // layer III
+extern const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I;
+extern const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II;
 extern const char *MEDIA_MIMETYPE_AUDIO_AAC;
 extern const char *MEDIA_MIMETYPE_AUDIO_QCELP;
 extern const char *MEDIA_MIMETYPE_AUDIO_VORBIS;
@@ -47,6 +49,7 @@
 extern const char *MEDIA_MIMETYPE_CONTAINER_MATROSKA;
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG2TS;
 extern const char *MEDIA_MIMETYPE_CONTAINER_AVI;
+extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG2PS;
 
 extern const char *MEDIA_MIMETYPE_CONTAINER_WVM;
 
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index ea022a6..1242e49 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -83,7 +83,11 @@
         eOrientationUnchanged   = 4,
         eOrientationSwapMask    = 0x01
     };
-    
+
+    enum {
+        eSynchronous            = 0x01,
+    };
+
     enum {
         eElectronBeamAnimationOn  = 0x01,
         eElectronBeamAnimationOff = 0x10
@@ -103,7 +107,7 @@
 
     /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
     virtual void setTransactionState(const Vector<ComposerState>& state,
-            int orientation) = 0;
+            int orientation, uint32_t flags) = 0;
 
     /* signal that we're done booting.
      * Requires ACCESS_SURFACE_FLINGER permission
@@ -142,8 +146,6 @@
         GET_CBLK,
         SET_TRANSACTION_STATE,
         SET_ORIENTATION,
-        FREEZE_DISPLAY,
-        UNFREEZE_DISPLAY,
         CAPTURE_SCREEN,
         TURN_ELECTRON_BEAM_OFF,
         TURN_ELECTRON_BEAM_ON,
diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h
index 14e5b23..8226abe 100644
--- a/include/surfaceflinger/SurfaceComposerClient.h
+++ b/include/surfaceflinger/SurfaceComposerClient.h
@@ -112,7 +112,7 @@
     static void openGlobalTransaction();
         
     //! Close a composer transaction on all active SurfaceComposerClients.
-    static void closeGlobalTransaction();
+    static void closeGlobalTransaction(bool synchronous = false);
     
     //! Freeze the specified display but not transactions.
     static status_t freezeDisplay(DisplayID dpy, uint32_t flags = 0);
diff --git a/include/utils/Singleton.h b/include/utils/Singleton.h
index e1ee8eb..a42ce21 100644
--- a/include/utils/Singleton.h
+++ b/include/utils/Singleton.h
@@ -20,12 +20,13 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <utils/threads.h>
+#include <cutils/compiler.h>
 
 namespace android {
 // ---------------------------------------------------------------------------
 
 template <typename TYPE>
-class Singleton
+class ANDROID_API Singleton
 {
 public:
     static TYPE& getInstance() {
diff --git a/libs/binder/CursorWindow.cpp b/libs/binder/CursorWindow.cpp
index 1b85a71..bf8d7a6 100644
--- a/libs/binder/CursorWindow.cpp
+++ b/libs/binder/CursorWindow.cpp
@@ -40,11 +40,9 @@
     ::close(mAshmemFd);
 }
 
-status_t CursorWindow::create(const String8& name, size_t size, bool localOnly,
-        CursorWindow** outCursorWindow) {
+status_t CursorWindow::create(const String8& name, size_t size, CursorWindow** outCursorWindow) {
     String8 ashmemName("CursorWindow: ");
     ashmemName.append(name);
-    ashmemName.append(localOnly ? " (local)" : " (remote)");
 
     status_t result;
     int ashmemFd = ashmem_create_region(ashmemName.string(), size);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index eb90147..86bc62a 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -79,7 +79,7 @@
     }
 
     virtual void setTransactionState(const Vector<ComposerState>& state,
-            int orientation)
+            int orientation, uint32_t flags)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -90,6 +90,7 @@
             b->write(data);
         }
         data.writeInt32(orientation);
+        data.writeInt32(flags);
         remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply);
     }
 
@@ -204,7 +205,8 @@
                 state.add(s);
             }
             int orientation = data.readInt32();
-            setTransactionState(state, orientation);
+            uint32_t flags = data.readInt32();
+            setTransactionState(state, orientation, flags);
         } break;
         case BOOT_FINISHED: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 5f3d608..4ad6c22 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -92,11 +92,14 @@
     mutable Mutex               mLock;
     SortedVector<ComposerState> mStates;
     int                         mOrientation;
+    uint32_t                    mForceSynchronous;
 
     Composer() : Singleton<Composer>(),
-        mOrientation(ISurfaceComposer::eOrientationUnchanged) { }
+        mOrientation(ISurfaceComposer::eOrientationUnchanged),
+        mForceSynchronous(0)
+    { }
 
-    void closeGlobalTransactionImpl();
+    void closeGlobalTransactionImpl(bool synchronous);
 
     layer_state_t* getLayerStateLocked(
             const sp<SurfaceComposerClient>& client, SurfaceID id);
@@ -123,8 +126,8 @@
             uint32_t tint);
     status_t setOrientation(int orientation);
 
-    static void closeGlobalTransaction() {
-        Composer::getInstance().closeGlobalTransactionImpl();
+    static void closeGlobalTransaction(bool synchronous) {
+        Composer::getInstance().closeGlobalTransactionImpl(synchronous);
     }
 };
 
@@ -132,11 +135,12 @@
 
 // ---------------------------------------------------------------------------
 
-void Composer::closeGlobalTransactionImpl() {
+void Composer::closeGlobalTransactionImpl(bool synchronous) {
     sp<ISurfaceComposer> sm(getComposerService());
 
     Vector<ComposerState> transaction;
     int orientation;
+    uint32_t flags = 0;
 
     { // scope for the lock
         Mutex::Autolock _l(mLock);
@@ -145,9 +149,14 @@
 
         orientation = mOrientation;
         mOrientation = ISurfaceComposer::eOrientationUnchanged;
+
+        if (synchronous || mForceSynchronous) {
+            flags |= ISurfaceComposer::eSynchronous;
+        }
+        mForceSynchronous = false;
     }
 
-   sm->setTransactionState(transaction, orientation);
+   sm->setTransactionState(transaction, orientation, flags);
 }
 
 layer_state_t* Composer::getLayerStateLocked(
@@ -188,6 +197,10 @@
     s->what |= ISurfaceComposer::eSizeChanged;
     s->w = w;
     s->h = h;
+
+    // Resizing a surface makes the transaction synchronous.
+    mForceSynchronous = true;
+
     return NO_ERROR;
 }
 
@@ -270,6 +283,10 @@
 status_t Composer::setOrientation(int orientation) {
     Mutex::Autolock _l(mLock);
     mOrientation = orientation;
+
+    // Changing the orientation makes the transaction synchronous.
+    mForceSynchronous = true;
+
     return NO_ERROR;
 }
 
@@ -375,8 +392,8 @@
     // Currently a no-op
 }
 
-void SurfaceComposerClient::closeGlobalTransaction() {
-    Composer::closeGlobalTransaction();
+void SurfaceComposerClient::closeGlobalTransaction(bool synchronous) {
+    Composer::closeGlobalTransaction(synchronous);
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index a98e4cd..9bfc94c 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -39,6 +39,7 @@
 		external/skia/include/utils
 
 	LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER
+	LOCAL_CFLAGS += -fvisibility=hidden
 	LOCAL_MODULE_CLASS := SHARED_LIBRARIES
 	LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia libui
 	LOCAL_MODULE := libhwui
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index cdcbf21..9b0d7c6 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -23,6 +23,8 @@
 
 #include <utils/Singleton.h>
 
+#include <cutils/compiler.h>
+
 #include "Extensions.h"
 #include "FontRenderer.h"
 #include "GammaFontRenderer.h"
@@ -82,7 +84,7 @@
 // Caches
 ///////////////////////////////////////////////////////////////////////////////
 
-class Caches: public Singleton<Caches> {
+class ANDROID_API Caches: public Singleton<Caches> {
     Caches();
     ~Caches();
 
diff --git a/libs/hwui/DisplayListLogBuffer.h b/libs/hwui/DisplayListLogBuffer.h
index bf16f29..5d689bb 100644
--- a/libs/hwui/DisplayListLogBuffer.h
+++ b/libs/hwui/DisplayListLogBuffer.h
@@ -18,6 +18,7 @@
 #define ANDROID_HWUI_DISPLAY_LIST_LOG_BUFFER_H
 
 #include <utils/Singleton.h>
+
 #include <stdio.h>
 
 namespace android {
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 8cd7fea..ab475bf 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -26,6 +26,8 @@
 #include <SkTDArray.h>
 #include <SkTSearch.h>
 
+#include <cutils/compiler.h>
+
 #include "DisplayListLogBuffer.h"
 #include "OpenGLRenderer.h"
 #include "utils/Functor.h"
@@ -58,7 +60,7 @@
 class DisplayList {
 public:
     DisplayList(const DisplayListRenderer& recorder);
-    ~DisplayList();
+    ANDROID_API ~DisplayList();
 
     // IMPORTANT: Update the intialization of OP_NAMES in the .cpp file
     //            when modifying this file
@@ -107,13 +109,13 @@
 
     void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
 
-    size_t getSize();
+    ANDROID_API size_t getSize();
 
     bool replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level = 0);
 
     void output(OpenGLRenderer& renderer, uint32_t level = 0);
 
-    static void outputLogBuffer(int fd);
+    ANDROID_API static void outputLogBuffer(int fd);
 
     void setRenderable(bool renderable) {
         mIsRenderable = renderable;
@@ -230,75 +232,76 @@
  */
 class DisplayListRenderer: public OpenGLRenderer {
 public:
-    DisplayListRenderer();
-    ~DisplayListRenderer();
+    ANDROID_API DisplayListRenderer();
+    virtual ~DisplayListRenderer();
 
-    DisplayList* getDisplayList(DisplayList* displayList);
+    ANDROID_API DisplayList* getDisplayList(DisplayList* displayList);
 
-    void setViewport(int width, int height);
-    void prepareDirty(float left, float top, float right, float bottom, bool opaque);
-    void finish();
+    virtual void setViewport(int width, int height);
+    virtual void prepareDirty(float left, float top, float right, float bottom, bool opaque);
+    virtual void finish();
 
-    bool callDrawGLFunction(Functor *functor, Rect& dirty);
+    virtual bool callDrawGLFunction(Functor *functor, Rect& dirty);
 
-    void interrupt();
-    void resume();
+    virtual void interrupt();
+    virtual void resume();
 
-    int save(int flags);
-    void restore();
-    void restoreToCount(int saveCount);
+    virtual int save(int flags);
+    virtual void restore();
+    virtual void restoreToCount(int saveCount);
 
-    int saveLayer(float left, float top, float right, float bottom,
+    virtual int saveLayer(float left, float top, float right, float bottom,
             SkPaint* p, int flags);
-    int saveLayerAlpha(float left, float top, float right, float bottom,
+    virtual int saveLayerAlpha(float left, float top, float right, float bottom,
                 int alpha, int flags);
 
-    void translate(float dx, float dy);
-    void rotate(float degrees);
-    void scale(float sx, float sy);
-    void skew(float sx, float sy);
+    virtual void translate(float dx, float dy);
+    virtual void rotate(float degrees);
+    virtual void scale(float sx, float sy);
+    virtual void skew(float sx, float sy);
 
-    void setMatrix(SkMatrix* matrix);
-    void concatMatrix(SkMatrix* matrix);
+    virtual void setMatrix(SkMatrix* matrix);
+    virtual void concatMatrix(SkMatrix* matrix);
 
-    bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
+    virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
 
-    bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
+    virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
             Rect& dirty, uint32_t level = 0);
-    void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
-    void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
-    void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
-    void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
+    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);
+    virtual void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
             float srcRight, float srcBottom, float dstLeft, float dstTop,
             float dstRight, float dstBottom, SkPaint* paint);
-    void drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
+    virtual void drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
             float* vertices, int* colors, SkPaint* paint);
-    void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
+    virtual void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
             const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
             float left, float top, float right, float bottom, SkPaint* paint);
-    void drawColor(int color, SkXfermode::Mode mode);
-    void drawRect(float left, float top, float right, float bottom, SkPaint* paint);
-    void drawRoundRect(float left, float top, float right, float bottom,
+    virtual void drawColor(int color, SkXfermode::Mode mode);
+    virtual void drawRect(float left, float top, float right, float bottom, SkPaint* paint);
+    virtual void drawRoundRect(float left, float top, float right, float bottom,
             float rx, float ry, SkPaint* paint);
-    void drawCircle(float x, float y, float radius, SkPaint* paint);
-    void drawOval(float left, float top, float right, float bottom, SkPaint* paint);
-    void drawArc(float left, float top, float right, float bottom,
+    virtual void drawCircle(float x, float y, float radius, SkPaint* paint);
+    virtual void drawOval(float left, float top, float right, float bottom, SkPaint* paint);
+    virtual void drawArc(float left, float top, float right, float bottom,
             float startAngle, float sweepAngle, bool useCenter, SkPaint* paint);
-    void drawPath(SkPath* path, SkPaint* paint);
-    void drawLines(float* points, int count, SkPaint* paint);
-    void drawPoints(float* points, int count, SkPaint* paint);
-    void drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint);
+    virtual void drawPath(SkPath* path, SkPaint* paint);
+    virtual void drawLines(float* points, int count, SkPaint* paint);
+    virtual void drawPoints(float* points, int count, SkPaint* paint);
+    virtual void drawText(const char* text, int bytesCount, int count, float x, float y,
+            SkPaint* paint);
 
-    void resetShader();
-    void setupShader(SkiaShader* shader);
+    virtual void resetShader();
+    virtual void setupShader(SkiaShader* shader);
 
-    void resetColorFilter();
-    void setupColorFilter(SkiaColorFilter* filter);
+    virtual void resetColorFilter();
+    virtual void setupColorFilter(SkiaColorFilter* filter);
 
-    void resetShadow();
-    void setupShadow(float radius, float dx, float dy, int color);
+    virtual void resetShadow();
+    virtual void setupShadow(float radius, float dx, float dy, int color);
 
-    void reset();
+    ANDROID_API void reset();
 
     const SkWriter32& writeStream() const {
         return mWriter;
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 349b9e3..dfcc5ea 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -31,6 +31,12 @@
 // Rendering
 ///////////////////////////////////////////////////////////////////////////////
 
+LayerRenderer::LayerRenderer(Layer* layer): mLayer(layer) {
+}
+
+LayerRenderer::~LayerRenderer() {
+}
+
 void LayerRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) {
     LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->getFbo());
 
@@ -264,7 +270,7 @@
     layer->setFbo(0);
     layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
     layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f);
-    layer->texCoords.set(0.0f, 1.0f, 0.0f, 1.0f);
+    layer->texCoords.set(0.0f, 1.0f, 1.0f, 0.0f);
     layer->region.clear();
     layer->setRenderTarget(GL_NONE); // see ::updateTextureLayer()
 
@@ -400,6 +406,18 @@
             renderer.setViewport(bitmap->width(), bitmap->height());
             renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f,
                     bitmap->width(), bitmap->height(), !layer->isBlend());
+
+            glDisable(GL_SCISSOR_TEST);
+            renderer.translate(0.0f, bitmap->height());
+            renderer.scale(1.0f, -1.0f);
+
+            mat4 texTransform(layer->getTexTransform());
+
+            mat4 invert;
+            invert.translate(0.0f, 1.0f, 0.0f);
+            invert.scale(1.0f, -1.0f, 1.0f);
+            layer->getTexTransform().multiply(invert);
+
             if ((error = glGetError()) != GL_NO_ERROR) goto error;
 
             {
@@ -413,6 +431,7 @@
                 if ((error = glGetError()) != GL_NO_ERROR) goto error;
             }
 
+            layer->getTexTransform().load(texTransform);
             status = true;
         }
 
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index 2246573..6104301 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_HWUI_LAYER_RENDERER_H
 #define ANDROID_HWUI_LAYER_RENDERER_H
 
+#include <cutils/compiler.h>
+
 #include "OpenGLRenderer.h"
 #include "Layer.h"
 
@@ -42,27 +44,24 @@
 
 class LayerRenderer: public OpenGLRenderer {
 public:
-    LayerRenderer(Layer* layer): mLayer(layer) {
-    }
+    ANDROID_API LayerRenderer(Layer* layer);
+    virtual ~LayerRenderer();
 
-    ~LayerRenderer() {
-    }
+    virtual void prepareDirty(float left, float top, float right, float bottom, bool opaque);
+    virtual void finish();
 
-    void prepareDirty(float left, float top, float right, float bottom, bool opaque);
-    void finish();
+    virtual bool hasLayer();
+    virtual Region* getRegion();
+    virtual GLint getTargetFbo();
 
-    bool hasLayer();
-    Region* getRegion();
-    GLint getTargetFbo();
-
-    static Layer* createTextureLayer(bool isOpaque);
-    static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false);
-    static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
-    static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
+    ANDROID_API static Layer* createTextureLayer(bool isOpaque);
+    ANDROID_API static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false);
+    ANDROID_API static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
+    ANDROID_API static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
             bool isOpaque, GLenum renderTarget, float* transform);
-    static void destroyLayer(Layer* layer);
-    static void destroyLayerDeferred(Layer* layer);
-    static bool copyLayer(Layer* layer, SkBitmap* bitmap);
+    ANDROID_API static void destroyLayer(Layer* layer);
+    ANDROID_API static void destroyLayerDeferred(Layer* layer);
+    ANDROID_API static bool copyLayer(Layer* layer, SkBitmap* bitmap);
 
 private:
     void generateMesh();
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 56fd37d..22220a9 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -19,6 +19,8 @@
 
 #include <SkMatrix.h>
 
+#include <cutils/compiler.h>
+
 #include "Rect.h"
 
 namespace android {
@@ -28,7 +30,7 @@
 // Classes
 ///////////////////////////////////////////////////////////////////////////////
 
-class Matrix4 {
+class ANDROID_API Matrix4 {
 public:
     float data[16];
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 14b22b3..2fc88e1 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -31,6 +31,8 @@
 #include <utils/RefBase.h>
 #include <utils/Vector.h>
 
+#include <cutils/compiler.h>
+
 #include "Debug.h"
 #include "Extensions.h"
 #include "Matrix.h"
@@ -57,12 +59,12 @@
  */
 class OpenGLRenderer {
 public:
-    OpenGLRenderer();
+    ANDROID_API OpenGLRenderer();
     virtual ~OpenGLRenderer();
 
     virtual void setViewport(int width, int height);
 
-    void prepare(bool opaque);
+    ANDROID_API void prepare(bool opaque);
     virtual void prepareDirty(float left, float top, float right, float bottom, bool opaque);
     virtual void finish();
 
@@ -72,7 +74,7 @@
 
     virtual bool callDrawGLFunction(Functor *functor, Rect& dirty);
 
-    int getSaveCount() const;
+    ANDROID_API int getSaveCount() const;
     virtual int save(int flags);
     virtual void restore();
     virtual void restoreToCount(int saveCount);
@@ -87,12 +89,12 @@
     virtual void scale(float sx, float sy);
     virtual void skew(float sx, float sy);
 
-    void getMatrix(SkMatrix* matrix);
+    ANDROID_API void getMatrix(SkMatrix* matrix);
     virtual void setMatrix(SkMatrix* matrix);
     virtual void concatMatrix(SkMatrix* matrix);
 
-    const Rect& getClipBounds();
-    bool quickReject(float left, float top, float right, float bottom);
+    ANDROID_API const Rect& getClipBounds();
+    ANDROID_API bool quickReject(float left, float top, float right, float bottom);
     virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
 
     virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index 2a38910..8cf466b 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_HWUI_RESOURCE_CACHE_H
 #define ANDROID_HWUI_RESOURCE_CACHE_H
 
+#include <cutils/compiler.h>
+
 #include <SkBitmap.h>
 #include <SkiaColorFilter.h>
 #include <SkiaShader.h>
@@ -49,7 +51,7 @@
     ResourceType resourceType;
 };
 
-class ResourceCache {
+class ANDROID_API ResourceCache {
     KeyedVector<void *, ResourceReference *>* mCache;
 public:
     ResourceCache();
diff --git a/libs/hwui/SkiaColorFilter.h b/libs/hwui/SkiaColorFilter.h
index 1bf475c..2feb834 100644
--- a/libs/hwui/SkiaColorFilter.h
+++ b/libs/hwui/SkiaColorFilter.h
@@ -20,6 +20,8 @@
 #include <GLES2/gl2.h>
 #include <SkColorFilter.h>
 
+#include <cutils/compiler.h>
+
 #include "ProgramCache.h"
 #include "Extensions.h"
 
@@ -45,7 +47,7 @@
         kBlend,
     };
 
-    SkiaColorFilter(SkColorFilter *skFilter, Type type, bool blend);
+    ANDROID_API SkiaColorFilter(SkColorFilter *skFilter, Type type, bool blend);
     virtual ~SkiaColorFilter();
 
     virtual void describe(ProgramDescription& description, const Extensions& extensions) = 0;
@@ -79,7 +81,7 @@
  * A color filter that multiplies the source color with a matrix and adds a vector.
  */
 struct SkiaColorMatrixFilter: public SkiaColorFilter {
-    SkiaColorMatrixFilter(SkColorFilter *skFilter, float* matrix, float* vector);
+    ANDROID_API SkiaColorMatrixFilter(SkColorFilter *skFilter, float* matrix, float* vector);
     ~SkiaColorMatrixFilter();
 
     void describe(ProgramDescription& description, const Extensions& extensions);
@@ -95,7 +97,7 @@
  * another fixed value. Ignores the alpha channel of both arguments.
  */
 struct SkiaLightingFilter: public SkiaColorFilter {
-    SkiaLightingFilter(SkColorFilter *skFilter, int multiply, int add);
+    ANDROID_API SkiaLightingFilter(SkColorFilter *skFilter, int multiply, int add);
 
     void describe(ProgramDescription& description, const Extensions& extensions);
     void setupProgram(Program* program);
@@ -110,7 +112,7 @@
  * and PorterDuff blending mode.
  */
 struct SkiaBlendFilter: public SkiaColorFilter {
-    SkiaBlendFilter(SkColorFilter *skFilter, int color, SkXfermode::Mode mode);
+    ANDROID_API SkiaBlendFilter(SkColorFilter *skFilter, int color, SkXfermode::Mode mode);
 
     void describe(ProgramDescription& description, const Extensions& extensions);
     void setupProgram(Program* program);
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index 89dd131..2de9a93 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -22,6 +22,8 @@
 
 #include <GLES2/gl2.h>
 
+#include <cutils/compiler.h>
+
 #include "Extensions.h"
 #include "ProgramCache.h"
 #include "TextureCache.h"
@@ -52,8 +54,8 @@
         kCompose
     };
 
-    SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX, SkShader::TileMode tileY,
-            SkMatrix* matrix, bool blend);
+    ANDROID_API SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX,
+            SkShader::TileMode tileY, SkMatrix* matrix, bool blend);
     virtual ~SkiaShader();
 
     virtual SkiaShader* copy() = 0;
@@ -139,7 +141,7 @@
  * A shader that draws a bitmap.
  */
 struct SkiaBitmapShader: public SkiaShader {
-    SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX,
+    ANDROID_API SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX,
             SkShader::TileMode tileY, SkMatrix* matrix, bool blend);
     SkiaShader* copy();
 
@@ -169,8 +171,8 @@
  * A shader that draws a linear gradient.
  */
 struct SkiaLinearGradientShader: public SkiaShader {
-    SkiaLinearGradientShader(float* bounds, uint32_t* colors, float* positions, int count,
-            SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
+    ANDROID_API SkiaLinearGradientShader(float* bounds, uint32_t* colors, float* positions,
+            int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
     ~SkiaLinearGradientShader();
     SkiaShader* copy();
 
@@ -193,8 +195,8 @@
  * A shader that draws a sweep gradient.
  */
 struct SkiaSweepGradientShader: public SkiaShader {
-    SkiaSweepGradientShader(float x, float y, uint32_t* colors, float* positions, int count,
-            SkShader* key, SkMatrix* matrix, bool blend);
+    ANDROID_API SkiaSweepGradientShader(float x, float y, uint32_t* colors, float* positions,
+            int count, SkShader* key, SkMatrix* matrix, bool blend);
     ~SkiaSweepGradientShader();
     SkiaShader* copy();
 
@@ -218,8 +220,9 @@
  * A shader that draws a circular gradient.
  */
 struct SkiaCircularGradientShader: public SkiaSweepGradientShader {
-    SkiaCircularGradientShader(float x, float y, float radius, uint32_t* colors, float* positions,
-            int count, SkShader* key,SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
+    ANDROID_API SkiaCircularGradientShader(float x, float y, float radius, uint32_t* colors,
+            float* positions, int count, SkShader* key,SkShader::TileMode tileMode,
+            SkMatrix* matrix, bool blend);
     SkiaShader* copy();
 
     void describe(ProgramDescription& description, const Extensions& extensions);
@@ -233,7 +236,8 @@
  * A shader that draws two shaders, composited with an xfermode.
  */
 struct SkiaComposeShader: public SkiaShader {
-    SkiaComposeShader(SkiaShader* first, SkiaShader* second, SkXfermode::Mode mode, SkShader* key);
+    ANDROID_API SkiaComposeShader(SkiaShader* first, SkiaShader* second, SkXfermode::Mode mode,
+            SkShader* key);
     ~SkiaComposeShader();
     SkiaShader* copy();
 
diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp
index 5fd5c35..4ecf8e8 100644
--- a/libs/rs/driver/rsdBcc.cpp
+++ b/libs/rs/driver/rsdBcc.cpp
@@ -226,6 +226,7 @@
     RsdHal * dc = (RsdHal *)mtls->rsc->mHal.drv;
     uint32_t sig = mtls->sig;
 
+    outer_foreach_t fn = dc->mForEachLaunch[sig];
     while (1) {
         uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
         uint32_t yStart = mtls->yStart + slice * mtls->mSliceSize;
@@ -239,16 +240,10 @@
         //LOGE("usr ptr in %p,  out %p", mtls->ptrIn, mtls->ptrOut);
         for (p.y = yStart; p.y < yEnd; p.y++) {
             uint32_t offset = mtls->dimX * p.y;
-            uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * offset);
-            const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * offset);
-
-            for (p.x = mtls->xStart; p.x < mtls->xEnd; p.x++) {
-                p.in = xPtrIn;
-                p.out = xPtrOut;
-                dc->mForEachLaunch[sig](&mtls->script->mHal.info.root, &p);
-                xPtrIn += mtls->eStrideIn;
-                xPtrOut += mtls->eStrideOut;
-            }
+            p.out = mtls->ptrOut + (mtls->eStrideOut * offset);
+            p.in = mtls->ptrIn + (mtls->eStrideIn * offset);
+            fn(&mtls->script->mHal.info.root, &p, mtls->xStart, mtls->xEnd,
+               mtls->eStrideIn, mtls->eStrideOut);
         }
     }
 }
@@ -262,6 +257,7 @@
     RsdHal * dc = (RsdHal *)mtls->rsc->mHal.drv;
     uint32_t sig = mtls->sig;
 
+    outer_foreach_t fn = dc->mForEachLaunch[sig];
     while (1) {
         uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
         uint32_t xStart = mtls->xStart + slice * mtls->mSliceSize;
@@ -271,17 +267,12 @@
             return;
         }
 
-        //LOGE("usr idx %i, x %i,%i  y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd);
+        //LOGE("usr slice %i idx %i, x %i,%i", slice, idx, xStart, xEnd);
         //LOGE("usr ptr in %p,  out %p", mtls->ptrIn, mtls->ptrOut);
-        uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * xStart);
-        const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * xStart);
-        for (p.x = xStart; p.x < xEnd; p.x++) {
-            p.in = xPtrIn;
-            p.out = xPtrOut;
-            dc->mForEachLaunch[sig](&mtls->script->mHal.info.root, &p);
-            xPtrIn += mtls->eStrideIn;
-            xPtrOut += mtls->eStrideOut;
-        }
+
+        p.out = mtls->ptrOut + (mtls->eStrideOut * xStart);
+        p.in = mtls->ptrIn + (mtls->eStrideIn * xStart);
+        fn(&mtls->script->mHal.info.root, &p, xStart, xEnd, mtls->eStrideIn, mtls->eStrideOut);
     }
 }
 
@@ -392,22 +383,17 @@
         uint32_t sig = mtls.sig;
 
         //LOGE("launch 3");
+        outer_foreach_t fn = dc->mForEachLaunch[sig];
         for (p.ar[0] = mtls.arrayStart; p.ar[0] < mtls.arrayEnd; p.ar[0]++) {
             for (p.z = mtls.zStart; p.z < mtls.zEnd; p.z++) {
                 for (p.y = mtls.yStart; p.y < mtls.yEnd; p.y++) {
                     uint32_t offset = mtls.dimX * mtls.dimY * mtls.dimZ * p.ar[0] +
                                       mtls.dimX * mtls.dimY * p.z +
                                       mtls.dimX * p.y;
-                    uint8_t *xPtrOut = mtls.ptrOut + (mtls.eStrideOut * offset);
-                    const uint8_t *xPtrIn = mtls.ptrIn + (mtls.eStrideIn * offset);
-
-                    for (p.x = mtls.xStart; p.x < mtls.xEnd; p.x++) {
-                        p.in = xPtrIn;
-                        p.out = xPtrOut;
-                        dc->mForEachLaunch[sig](&s->mHal.info.root, &p);
-                        xPtrIn += mtls.eStrideIn;
-                        xPtrOut += mtls.eStrideOut;
-                    }
+                    p.out = mtls.ptrOut + (mtls.eStrideOut * offset);
+                    p.in = mtls.ptrIn + (mtls.eStrideIn * offset);
+                    fn(&mtls.script->mHal.info.root, &p, mtls.xStart, mtls.xEnd,
+                       mtls.eStrideIn, mtls.eStrideOut);
                 }
             }
         }
diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp
index f8107d9..247f4dc 100644
--- a/libs/rs/driver/rsdCore.cpp
+++ b/libs/rs/driver/rsdCore.cpp
@@ -292,75 +292,136 @@
 }
 
 static void rsdForEach17(const void *vRoot,
-        const android::renderscript::RsForEachStubParamStruct *p) {
+        const android::renderscript::RsForEachStubParamStruct *p,
+                                uint32_t x1, uint32_t x2,
+                                uint32_t instep, uint32_t outstep) {
     typedef void (*fe)(const void *, uint32_t);
     (*(fe*)vRoot)(p->in, p->y);
 }
 
 static void rsdForEach18(const void *vRoot,
-        const android::renderscript::RsForEachStubParamStruct *p) {
+        const android::renderscript::RsForEachStubParamStruct *p,
+                                uint32_t x1, uint32_t x2,
+                                uint32_t instep, uint32_t outstep) {
     typedef void (*fe)(void *, uint32_t);
     (*(fe*)vRoot)(p->out, p->y);
 }
 
 static void rsdForEach19(const void *vRoot,
-        const android::renderscript::RsForEachStubParamStruct *p) {
+        const android::renderscript::RsForEachStubParamStruct *p,
+                                uint32_t x1, uint32_t x2,
+                                uint32_t instep, uint32_t outstep) {
     typedef void (*fe)(const void *, void *, uint32_t);
     (*(fe*)vRoot)(p->in, p->out, p->y);
 }
 
 static void rsdForEach21(const void *vRoot,
-        const android::renderscript::RsForEachStubParamStruct *p) {
+        const android::renderscript::RsForEachStubParamStruct *p,
+                                uint32_t x1, uint32_t x2,
+                                uint32_t instep, uint32_t outstep) {
     typedef void (*fe)(const void *, const void *, uint32_t);
     (*(fe*)vRoot)(p->in, p->usr, p->y);
 }
 
 static void rsdForEach22(const void *vRoot,
-        const android::renderscript::RsForEachStubParamStruct *p) {
+        const android::renderscript::RsForEachStubParamStruct *p,
+                                uint32_t x1, uint32_t x2,
+                                uint32_t instep, uint32_t outstep) {
     typedef void (*fe)(void *, const void *, uint32_t);
     (*(fe*)vRoot)(p->out, p->usr, p->y);
 }
 
 static void rsdForEach23(const void *vRoot,
-        const android::renderscript::RsForEachStubParamStruct *p) {
+        const android::renderscript::RsForEachStubParamStruct *p,
+                                uint32_t x1, uint32_t x2,
+                                uint32_t instep, uint32_t outstep) {
     typedef void (*fe)(const void *, void *, const void *, uint32_t);
     (*(fe*)vRoot)(p->in, p->out, p->usr, p->y);
 }
 
 static void rsdForEach25(const void *vRoot,
-        const android::renderscript::RsForEachStubParamStruct *p) {
+        const android::renderscript::RsForEachStubParamStruct *p,
+                                uint32_t x1, uint32_t x2,
+                                uint32_t instep, uint32_t outstep) {
     typedef void (*fe)(const void *, uint32_t, uint32_t);
-    (*(fe*)vRoot)(p->in, p->x, p->y);
+    const uint8_t *pin = (const uint8_t *)p->in;
+    uint32_t y = p->y;
+    for (uint32_t x = x1; x < x2; x++) {
+        (*(fe*)vRoot)(pin, x, y);
+        pin += instep;
+    }
 }
 
 static void rsdForEach26(const void *vRoot,
-        const android::renderscript::RsForEachStubParamStruct *p) {
+        const android::renderscript::RsForEachStubParamStruct *p,
+                                uint32_t x1, uint32_t x2,
+                                uint32_t instep, uint32_t outstep) {
     typedef void (*fe)(void *, uint32_t, uint32_t);
-    (*(fe*)vRoot)(p->out, p->x, p->y);
+    uint8_t *pout = (uint8_t *)p->out;
+    uint32_t y = p->y;
+    for (uint32_t x = x1; x < x2; x++) {
+        (*(fe*)vRoot)(pout, x, y);
+        pout += outstep;
+    }
 }
 
 static void rsdForEach27(const void *vRoot,
-        const android::renderscript::RsForEachStubParamStruct *p) {
+        const android::renderscript::RsForEachStubParamStruct *p,
+                                uint32_t x1, uint32_t x2,
+                                uint32_t instep, uint32_t outstep) {
     typedef void (*fe)(const void *, void *, uint32_t, uint32_t);
-    (*(fe*)vRoot)(p->in, p->out, p->x, p->y);
+    uint8_t *pout = (uint8_t *)p->out;
+    const uint8_t *pin = (const uint8_t *)p->in;
+    uint32_t y = p->y;
+    for (uint32_t x = x1; x < x2; x++) {
+        (*(fe*)vRoot)(pin, pout, x, y);
+        pin += instep;
+        pout += outstep;
+    }
 }
 
 static void rsdForEach29(const void *vRoot,
-        const android::renderscript::RsForEachStubParamStruct *p) {
+        const android::renderscript::RsForEachStubParamStruct *p,
+                                uint32_t x1, uint32_t x2,
+                                uint32_t instep, uint32_t outstep) {
     typedef void (*fe)(const void *, const void *, uint32_t, uint32_t);
-    (*(fe*)vRoot)(p->in, p->usr, p->x, p->y);
+    const uint8_t *pin = (const uint8_t *)p->in;
+    const void *usr = p->usr;
+    const uint32_t y = p->y;
+    for (uint32_t x = x1; x < x2; x++) {
+        (*(fe*)vRoot)(pin, usr, x, y);
+        pin += instep;
+    }
 }
 
 static void rsdForEach30(const void *vRoot,
-        const android::renderscript::RsForEachStubParamStruct *p) {
+        const android::renderscript::RsForEachStubParamStruct *p,
+                                uint32_t x1, uint32_t x2,
+                                uint32_t instep, uint32_t outstep) {
     typedef void (*fe)(void *, const void *, uint32_t, uint32_t);
-    (*(fe*)vRoot)(p->out, p->usr, p->x, p->y);
+    uint8_t *pout = (uint8_t *)p->out;
+    const void *usr = p->usr;
+    const uint32_t y = p->y;
+    for (uint32_t x = x1; x < x2; x++) {
+        (*(fe*)vRoot)(pout, usr, x, y);
+        pout += outstep;
+    }
 }
 
 static void rsdForEach31(const void *vRoot,
-        const android::renderscript::RsForEachStubParamStruct *p) {
+        const android::renderscript::RsForEachStubParamStruct *p,
+                                uint32_t x1, uint32_t x2,
+                                uint32_t instep, uint32_t outstep) {
     typedef void (*fe)(const void *, void *, const void *, uint32_t, uint32_t);
-    (*(fe*)vRoot)(p->in, p->out, p->usr, p->x, p->y);
+    uint8_t *pout = (uint8_t *)p->out;
+    const uint8_t *pin = (const uint8_t *)p->in;
+    const void *usr = p->usr;
+    const uint32_t y = p->y;
+    for (uint32_t x = x1; x < x2; x++) {
+        (*(fe*)vRoot)(pin, pout, usr, x, y);
+        pin += instep;
+        pout += outstep;
+    }
 }
 
 
diff --git a/libs/rs/driver/rsdCore.h b/libs/rs/driver/rsdCore.h
index 159b72a..ce86d11 100644
--- a/libs/rs/driver/rsdCore.h
+++ b/libs/rs/driver/rsdCore.h
@@ -28,7 +28,9 @@
 typedef void (*WorkerCallback_t)(void *usr, uint32_t idx);
 
 typedef void (*outer_foreach_t)(const void *,
-    const android::renderscript::RsForEachStubParamStruct *);
+    const android::renderscript::RsForEachStubParamStruct *,
+                                uint32_t x1, uint32_t x2,
+                                uint32_t instep, uint32_t outstep);
 
 typedef struct RsdSymbolTableRec {
     const char * mName;
diff --git a/libs/rs/rsProgramRaster.h b/libs/rs/rsProgramRaster.h
index 20af30a..c552ea3 100644
--- a/libs/rs/rsProgramRaster.h
+++ b/libs/rs/rsProgramRaster.h
@@ -24,17 +24,16 @@
 namespace renderscript {
 
 class ProgramRasterState;
-
+/*****************************************************************************
+ * CAUTION
+ *
+ * Any layout changes for this class may require a corresponding change to be
+ * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains
+ * a partial copy of the information below.
+ *
+ *****************************************************************************/
 class ProgramRaster : public ProgramBase {
 public:
-    virtual void setup(const Context *, ProgramRasterState *);
-    virtual void serialize(OStream *stream) const;
-    virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_RASTER; }
-    static ProgramRaster *createFromStream(Context *rsc, IStream *stream);
-
-    static ObjectBaseRef<ProgramRaster> getProgramRaster(Context *rsc,
-                                                         bool pointSprite,
-                                                         RsCullMode cull);
     struct Hal {
         mutable void *drv;
 
@@ -46,6 +45,14 @@
     };
     Hal mHal;
 
+    virtual void setup(const Context *, ProgramRasterState *);
+    virtual void serialize(OStream *stream) const;
+    virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_RASTER; }
+    static ProgramRaster *createFromStream(Context *rsc, IStream *stream);
+
+    static ObjectBaseRef<ProgramRaster> getProgramRaster(Context *rsc,
+                                                         bool pointSprite,
+                                                         RsCullMode cull);
 protected:
     virtual void preDestroy() const;
     virtual ~ProgramRaster();
diff --git a/libs/rs/rsProgramStore.h b/libs/rs/rsProgramStore.h
index e21f039..9bb2795 100644
--- a/libs/rs/rsProgramStore.h
+++ b/libs/rs/rsProgramStore.h
@@ -25,23 +25,16 @@
 namespace renderscript {
 
 class ProgramStoreState;
-
+/*****************************************************************************
+ * CAUTION
+ *
+ * Any layout changes for this class may require a corresponding change to be
+ * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains
+ * a partial copy of the information below.
+ *
+ *****************************************************************************/
 class ProgramStore : public ProgramBase {
 public:
-    virtual void setup(const Context *, ProgramStoreState *);
-
-    virtual void serialize(OStream *stream) const;
-    virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_STORE; }
-    static ProgramStore *createFromStream(Context *rsc, IStream *stream);
-    static ObjectBaseRef<ProgramStore> getProgramStore(Context *,
-                                                       bool colorMaskR, bool colorMaskG,
-                                                       bool colorMaskB, bool colorMaskA,
-                                                       bool depthMask, bool ditherEnable,
-                                                       RsBlendSrcFunc srcFunc, RsBlendDstFunc destFunc,
-                                                       RsDepthFunc depthFunc);
-
-    void init();
-
     struct Hal {
         mutable void *drv;
 
@@ -64,6 +57,18 @@
     };
     Hal mHal;
 
+    virtual void setup(const Context *, ProgramStoreState *);
+
+    virtual void serialize(OStream *stream) const;
+    virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_STORE; }
+    static ProgramStore *createFromStream(Context *rsc, IStream *stream);
+    static ObjectBaseRef<ProgramStore> getProgramStore(Context *,
+                                                       bool colorMaskR, bool colorMaskG,
+                                                       bool colorMaskB, bool colorMaskA,
+                                                       bool depthMask, bool ditherEnable,
+                                                       RsBlendSrcFunc srcFunc, RsBlendDstFunc destFunc,
+                                                       RsDepthFunc depthFunc);
+    void init();
 protected:
     virtual void preDestroy() const;
     virtual ~ProgramStore();
diff --git a/libs/rs/rsSampler.h b/libs/rs/rsSampler.h
index e698132..654cd9c 100644
--- a/libs/rs/rsSampler.h
+++ b/libs/rs/rsSampler.h
@@ -27,23 +27,16 @@
 const static uint32_t RS_MAX_SAMPLER_SLOT = 16;
 
 class SamplerState;
-
+/*****************************************************************************
+ * CAUTION
+ *
+ * Any layout changes for this class may require a corresponding change to be
+ * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains
+ * a partial copy of the information below.
+ *
+ *****************************************************************************/
 class Sampler : public ObjectBase {
 public:
-    static ObjectBaseRef<Sampler> getSampler(Context *,
-                                             RsSamplerValue magFilter,
-                                             RsSamplerValue minFilter,
-                                             RsSamplerValue wrapS,
-                                             RsSamplerValue wrapT,
-                                             RsSamplerValue wrapR,
-                                             float aniso = 1.0f);
-    void bindToContext(SamplerState *, uint32_t slot);
-    void unbindFromContext(SamplerState *);
-
-    virtual void serialize(OStream *stream) const;
-    virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_SAMPLER; }
-    static Sampler *createFromStream(Context *rsc, IStream *stream);
-
     struct Hal {
         mutable void *drv;
 
@@ -59,6 +52,20 @@
     };
     Hal mHal;
 
+    static ObjectBaseRef<Sampler> getSampler(Context *,
+                                             RsSamplerValue magFilter,
+                                             RsSamplerValue minFilter,
+                                             RsSamplerValue wrapS,
+                                             RsSamplerValue wrapT,
+                                             RsSamplerValue wrapR,
+                                             float aniso = 1.0f);
+    void bindToContext(SamplerState *, uint32_t slot);
+    void unbindFromContext(SamplerState *);
+
+    virtual void serialize(OStream *stream) const;
+    virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_SAMPLER; }
+    static Sampler *createFromStream(Context *rsc, IStream *stream);
+
 protected:
     int32_t mBoundSlot;
 
diff --git a/libs/rs/scriptc/rs_graphics.rsh b/libs/rs/scriptc/rs_graphics.rsh
index 3e9339e..80267c7 100644
--- a/libs/rs/scriptc/rs_graphics.rsh
+++ b/libs/rs/scriptc/rs_graphics.rsh
@@ -23,6 +23,55 @@
 #ifndef __RS_GRAPHICS_RSH__
 #define __RS_GRAPHICS_RSH__
 
+// These are API 15 once it get official
+typedef enum {
+    RS_DEPTH_FUNC_ALWAYS,
+    RS_DEPTH_FUNC_LESS,
+    RS_DEPTH_FUNC_LEQUAL,
+    RS_DEPTH_FUNC_GREATER,
+    RS_DEPTH_FUNC_GEQUAL,
+    RS_DEPTH_FUNC_EQUAL,
+    RS_DEPTH_FUNC_NOTEQUAL
+} rs_depth_func;
+
+typedef enum {
+    RS_BLEND_SRC_ZERO,                  // 0
+    RS_BLEND_SRC_ONE,                   // 1
+    RS_BLEND_SRC_DST_COLOR,             // 2
+    RS_BLEND_SRC_ONE_MINUS_DST_COLOR,   // 3
+    RS_BLEND_SRC_SRC_ALPHA,             // 4
+    RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA,   // 5
+    RS_BLEND_SRC_DST_ALPHA,             // 6
+    RS_BLEND_SRC_ONE_MINUS_DST_ALPHA,   // 7
+    RS_BLEND_SRC_SRC_ALPHA_SATURATE     // 8
+} rs_blend_src_func;
+
+typedef enum {
+    RS_BLEND_DST_ZERO,                  // 0
+    RS_BLEND_DST_ONE,                   // 1
+    RS_BLEND_DST_SRC_COLOR,             // 2
+    RS_BLEND_DST_ONE_MINUS_SRC_COLOR,   // 3
+    RS_BLEND_DST_SRC_ALPHA,             // 4
+    RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,   // 5
+    RS_BLEND_DST_DST_ALPHA,             // 6
+    RS_BLEND_DST_ONE_MINUS_DST_ALPHA    // 7
+} rs_blend_dst_func;
+
+typedef enum {
+    RS_CULL_BACK,
+    RS_CULL_FRONT,
+    RS_CULL_NONE
+} rs_cull_mode;
+
+typedef enum {
+    RS_SAMPLER_NEAREST,
+    RS_SAMPLER_LINEAR,
+    RS_SAMPLER_LINEAR_MIP_LINEAR,
+    RS_SAMPLER_WRAP,
+    RS_SAMPLER_CLAMP,
+    RS_SAMPLER_LINEAR_MIP_NEAREST,
+} rs_sampler_value;
+
 #if (defined(RS_VERSION) && (RS_VERSION >= 14))
 /**
  * Set the color target used for all subsequent rendering calls
@@ -83,6 +132,88 @@
 extern void __attribute__((overloadable))
     rsgBindProgramStore(rs_program_store ps);
 
+
+/**
+ * @hide
+ * Get program store depth function
+ *
+ * @param ps
+ */
+extern rs_depth_func __attribute__((overloadable))
+    rsgProgramStoreGetDepthFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store depth mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetDepthMask(rs_program_store ps);
+/**
+ * @hide
+ * Get program store red component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetColorMaskR(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store green component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetColorMaskG(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blur component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetColorMaskB(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store alpha component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetColorMaskA(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blend source function
+ *
+ * @param ps
+ */
+extern rs_blend_src_func __attribute__((overloadable))
+        rsgProgramStoreGetBlendSrcFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blend destination function
+ *
+ * @param ps
+ */
+extern rs_blend_dst_func __attribute__((overloadable))
+    rsgProgramStoreGetBlendDstFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store dither state
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetDitherEnabled(rs_program_store ps);
+
+
 /**
  * Bind a new ProgramVertex to the rendering context.
  *
@@ -100,6 +231,24 @@
     rsgBindProgramRaster(rs_program_raster pr);
 
 /**
+ * @hide
+ * Get program raster point sprite state
+ *
+ * @param pr
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramRasterGetPointSpriteEnabled(rs_program_raster pr);
+
+/**
+ * @hide
+ * Get program raster cull mode
+ *
+ * @param pr
+ */
+extern rs_cull_mode __attribute__((overloadable))
+    rsgProgramRasterGetCullMode(rs_program_raster pr);
+
+/**
  * Bind a new Sampler object to a ProgramFragment.  The sampler will
  * operate on the texture bound at the matching slot.
  *
@@ -109,6 +258,51 @@
     rsgBindSampler(rs_program_fragment, uint slot, rs_sampler);
 
 /**
+ * @hide
+ * Get sampler minification value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+    rsgSamplerGetMinification(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler magnification value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+    rsgSamplerGetMagnification(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler wrap S value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+    rsgSamplerGetWrapS(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler wrap T value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+    rsgSamplerGetWrapT(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler anisotropy
+ *
+ * @param pr
+ */
+extern float __attribute__((overloadable))
+    rsgSamplerGetAnisotropy(rs_sampler s);
+
+/**
  * Bind a new Allocation object to a ProgramFragment.  The
  * Allocation must be a valid texture for the Program.  The sampling
  * of the texture will be controled by the Sampler bound at the
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 8793841..e275aa6 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -71,6 +71,11 @@
     private static final int FIRST_VIDEO_FILE_TYPE = FILE_TYPE_MP4;
     private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_WEBM;
     
+    // More video file types
+    public static final int FILE_TYPE_MP2PS   = 200;
+    private static final int FIRST_VIDEO_FILE_TYPE2 = FILE_TYPE_MP2PS;
+    private static final int LAST_VIDEO_FILE_TYPE2 = FILE_TYPE_MP2PS;
+
     // Image file types
     public static final int FILE_TYPE_JPEG    = 31;
     public static final int FILE_TYPE_GIF     = 32;
@@ -235,6 +240,8 @@
         addFileType("PPT", FILE_TYPE_MS_POWERPOINT, "application/mspowerpoint", MtpConstants.FORMAT_MS_POWERPOINT_PRESENTATION);
         addFileType("FLAC", FILE_TYPE_FLAC, "audio/flac", MtpConstants.FORMAT_FLAC);
         addFileType("ZIP", FILE_TYPE_ZIP, "application/zip");
+        addFileType("MPG", FILE_TYPE_MP2PS, "video/mp2p");
+        addFileType("MPEG", FILE_TYPE_MP2PS, "video/mp2p");
     }
 
     public static boolean isAudioFileType(int fileType) {
@@ -246,7 +253,9 @@
 
     public static boolean isVideoFileType(int fileType) {
         return (fileType >= FIRST_VIDEO_FILE_TYPE &&
-                fileType <= LAST_VIDEO_FILE_TYPE);
+                fileType <= LAST_VIDEO_FILE_TYPE)
+            || (fileType >= FIRST_VIDEO_FILE_TYPE2 &&
+                fileType <= LAST_VIDEO_FILE_TYPE2);
     }
 
     public static boolean isImageFileType(int fileType) {
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index ec7d8a0..a3e2517 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -32,8 +32,8 @@
 	libdl
 
 LOCAL_STATIC_LIBRARIES := \
-        libstagefright_rtsp                     \
         libstagefright_nuplayer                 \
+        libstagefright_rtsp                     \
 
 LOCAL_C_INCLUDES :=                                                 \
 	$(JNI_H_INCLUDE)                                                \
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index b5eef94..24e1bfb 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -584,6 +584,10 @@
         }
     }
 
+    if (!strncasecmp("rtsp://", url, 7)) {
+        return NU_PLAYER;
+    }
+
     // use MidiFile for MIDI extensions
     int lenURL = strlen(url);
     for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk
index e761509..33e2f93 100644
--- a/media/libmediaplayerservice/nuplayer/Android.mk
+++ b/media/libmediaplayerservice/nuplayer/Android.mk
@@ -8,6 +8,7 @@
         NuPlayerDriver.cpp              \
         NuPlayerRenderer.cpp            \
         NuPlayerStreamListener.cpp      \
+        RTSPSource.cpp                  \
         StreamingSource.cpp             \
 
 LOCAL_C_INCLUDES := \
@@ -15,6 +16,7 @@
 	$(TOP)/frameworks/base/media/libstagefright/include             \
         $(TOP)/frameworks/base/media/libstagefright/mpeg2ts             \
         $(TOP)/frameworks/base/media/libstagefright/httplive            \
+        $(TOP)/frameworks/base/media/libstagefright/rtsp                \
 
 LOCAL_MODULE:= libstagefright_nuplayer
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 6b40528..4c710b4 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -25,6 +25,7 @@
 #include "NuPlayerDriver.h"
 #include "NuPlayerRenderer.h"
 #include "NuPlayerSource.h"
+#include "RTSPSource.h"
 #include "StreamingSource.h"
 
 #include "ATSParser.h"
@@ -87,7 +88,14 @@
         const char *url, const KeyedVector<String8, String8> *headers) {
     sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
 
-    msg->setObject("source", new HTTPLiveSource(url, headers, mUIDValid, mUID));
+    if (!strncasecmp(url, "rtsp://", 7)) {
+        msg->setObject(
+                "source", new RTSPSource(url, headers, mUIDValid, mUID));
+    } else {
+        msg->setObject(
+                "source", new HTTPLiveSource(url, headers, mUIDValid, mUID));
+    }
+
     msg->post();
 }
 
@@ -568,8 +576,15 @@
     CHECK(mAudioDecoder == NULL);
     CHECK(mVideoDecoder == NULL);
 
+    ++mScanSourcesGeneration;
+    mScanSourcesPending = false;
+
     mRenderer.clear();
-    mSource.clear();
+
+    if (mSource != NULL) {
+        mSource->stop();
+        mSource.clear();
+    }
 
     if (mDriver != NULL) {
         sp<NuPlayerDriver> driver = mDriver.promote();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index a5382b4..f90759d 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -68,6 +68,7 @@
     struct Renderer;
     struct Source;
     struct StreamingSource;
+    struct RTSPSource;
 
     enum {
         kWhatSetDataSource              = '=DaS',
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 07e347e..bf19040 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -219,7 +219,9 @@
 
 bool NuPlayer::Renderer::onDrainAudioQueue() {
     uint32_t numFramesPlayed;
-    CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
+    if (mAudioSink->getPosition(&numFramesPlayed) != OK) {
+        return false;
+    }
 
     ssize_t numFramesAvailableToWrite =
         mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 8a7eece..531b29f 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -28,6 +28,7 @@
     Source() {}
 
     virtual void start() = 0;
+    virtual void stop() {}
 
     // Returns OK iff more data was available,
     // an error or ERROR_END_OF_STREAM if not.
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
new file mode 100644
index 0000000..e72adc4
--- /dev/null
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "RTSPSource"
+#include <utils/Log.h>
+
+#include "RTSPSource.h"
+
+#include "AnotherPacketSource.h"
+#include "MyHandler.h"
+
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+NuPlayer::RTSPSource::RTSPSource(
+        const char *url,
+        const KeyedVector<String8, String8> *headers,
+        bool uidValid,
+        uid_t uid)
+    : mURL(url),
+      mUIDValid(uidValid),
+      mUID(uid),
+      mFlags(0),
+      mState(DISCONNECTED),
+      mFinalResult(OK),
+      mDisconnectReplyID(0) {
+    if (headers) {
+        mExtraHeaders = *headers;
+
+        ssize_t index =
+            mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
+
+        if (index >= 0) {
+            mFlags |= kFlagIncognito;
+
+            mExtraHeaders.removeItemsAt(index);
+        }
+    }
+}
+
+NuPlayer::RTSPSource::~RTSPSource() {
+    if (mLooper != NULL) {
+        mLooper->stop();
+    }
+}
+
+void NuPlayer::RTSPSource::start() {
+    if (mLooper == NULL) {
+        mLooper = new ALooper;
+        mLooper->setName("rtsp");
+        mLooper->start();
+
+        mReflector = new AHandlerReflector<RTSPSource>(this);
+        mLooper->registerHandler(mReflector);
+    }
+
+    CHECK(mHandler == NULL);
+
+    sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id());
+
+    mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID);
+    mLooper->registerHandler(mHandler);
+
+    CHECK_EQ(mState, (int)DISCONNECTED);
+    mState = CONNECTING;
+
+    mHandler->connect();
+}
+
+void NuPlayer::RTSPSource::stop() {
+    sp<AMessage> msg = new AMessage(kWhatDisconnect, mReflector->id());
+
+    sp<AMessage> dummy;
+    msg->postAndAwaitResponse(&dummy);
+}
+
+status_t NuPlayer::RTSPSource::feedMoreTSData() {
+    return mFinalResult;
+}
+
+sp<MetaData> NuPlayer::RTSPSource::getFormat(bool audio) {
+    sp<AnotherPacketSource> source = getSource(audio);
+
+    if (source == NULL) {
+        return NULL;
+    }
+
+    return source->getFormat();
+}
+
+status_t NuPlayer::RTSPSource::dequeueAccessUnit(
+        bool audio, sp<ABuffer> *accessUnit) {
+    sp<AnotherPacketSource> source = getSource(audio);
+
+    if (source == NULL) {
+        return -EWOULDBLOCK;
+    }
+
+    status_t finalResult;
+    if (!source->hasBufferAvailable(&finalResult)) {
+        return finalResult == OK ? -EWOULDBLOCK : finalResult;
+    }
+
+    return source->dequeueAccessUnit(accessUnit);
+}
+
+sp<AnotherPacketSource> NuPlayer::RTSPSource::getSource(bool audio) {
+    return audio ? mAudioTrack : mVideoTrack;
+}
+
+status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) {
+    *durationUs = 0ll;
+
+    int64_t audioDurationUs;
+    if (mAudioTrack != NULL
+            && mAudioTrack->getFormat()->findInt64(
+                kKeyDuration, &audioDurationUs)
+            && audioDurationUs > *durationUs) {
+        *durationUs = audioDurationUs;
+    }
+
+    int64_t videoDurationUs;
+    if (mVideoTrack != NULL
+            && mVideoTrack->getFormat()->findInt64(
+                kKeyDuration, &videoDurationUs)
+            && videoDurationUs > *durationUs) {
+        *durationUs = videoDurationUs;
+    }
+
+    return OK;
+}
+
+status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) {
+    if (mState != CONNECTED) {
+        return UNKNOWN_ERROR;
+    }
+
+    mState = SEEKING;
+    mHandler->seek(seekTimeUs);
+
+    return OK;
+}
+
+bool NuPlayer::RTSPSource::isSeekable() {
+    return true;
+}
+
+void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
+    if (msg->what() == kWhatDisconnect) {
+        uint32_t replyID;
+        CHECK(msg->senderAwaitsResponse(&replyID));
+
+        mDisconnectReplyID = replyID;
+        finishDisconnectIfPossible();
+        return;
+    }
+
+    CHECK_EQ(msg->what(), (int)kWhatNotify);
+
+    int32_t what;
+    CHECK(msg->findInt32("what", &what));
+
+    switch (what) {
+        case MyHandler::kWhatConnected:
+            onConnected();
+            break;
+
+        case MyHandler::kWhatDisconnected:
+            onDisconnected(msg);
+            break;
+
+        case MyHandler::kWhatSeekDone:
+        {
+            mState = CONNECTED;
+            break;
+        }
+
+        case MyHandler::kWhatAccessUnit:
+        {
+            size_t trackIndex;
+            CHECK(msg->findSize("trackIndex", &trackIndex));
+            CHECK_LT(trackIndex, mTracks.size());
+
+            sp<RefBase> obj;
+            CHECK(msg->findObject("accessUnit", &obj));
+
+            sp<ABuffer> accessUnit = static_cast<ABuffer *>(obj.get());
+
+            int32_t damaged;
+            if (accessUnit->meta()->findInt32("damaged", &damaged)
+                    && damaged) {
+                LOGI("dropping damaged access unit.");
+                break;
+            }
+
+            const TrackInfo &info = mTracks.editItemAt(trackIndex);
+            sp<AnotherPacketSource> source = info.mSource;
+            if (source != NULL) {
+#if 1
+                uint32_t rtpTime;
+                CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+
+                int64_t nptUs =
+                    ((double)rtpTime - (double)info.mRTPTime)
+                        / info.mTimeScale
+                        * 1000000ll
+                        + info.mNormalPlaytimeUs;
+
+                accessUnit->meta()->setInt64("timeUs", nptUs);
+#endif
+
+                source->queueAccessUnit(accessUnit);
+            }
+            break;
+        }
+
+        case MyHandler::kWhatEOS:
+        {
+            size_t trackIndex;
+            CHECK(msg->findSize("trackIndex", &trackIndex));
+            CHECK_LT(trackIndex, mTracks.size());
+
+            int32_t finalResult;
+            CHECK(msg->findInt32("finalResult", &finalResult));
+            CHECK_NE(finalResult, (status_t)OK);
+
+            TrackInfo *info = &mTracks.editItemAt(trackIndex);
+            sp<AnotherPacketSource> source = info->mSource;
+            if (source != NULL) {
+                source->signalEOS(finalResult);
+            }
+
+            break;
+        }
+
+        case MyHandler::kWhatSeekDiscontinuity:
+        {
+            size_t trackIndex;
+            CHECK(msg->findSize("trackIndex", &trackIndex));
+            CHECK_LT(trackIndex, mTracks.size());
+
+            TrackInfo *info = &mTracks.editItemAt(trackIndex);
+            sp<AnotherPacketSource> source = info->mSource;
+            if (source != NULL) {
+                source->queueDiscontinuity(ATSParser::DISCONTINUITY_SEEK, NULL);
+            }
+
+            break;
+        }
+
+        case MyHandler::kWhatNormalPlayTimeMapping:
+        {
+            size_t trackIndex;
+            CHECK(msg->findSize("trackIndex", &trackIndex));
+            CHECK_LT(trackIndex, mTracks.size());
+
+            uint32_t rtpTime;
+            CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime));
+
+            int64_t nptUs;
+            CHECK(msg->findInt64("nptUs", &nptUs));
+
+            TrackInfo *info = &mTracks.editItemAt(trackIndex);
+            info->mRTPTime = rtpTime;
+            info->mNormalPlaytimeUs = nptUs;
+            break;
+        }
+
+        default:
+            TRESPASS();
+    }
+}
+
+void NuPlayer::RTSPSource::onConnected() {
+    CHECK(mAudioTrack == NULL);
+    CHECK(mVideoTrack == NULL);
+
+    size_t numTracks = mHandler->countTracks();
+    for (size_t i = 0; i < numTracks; ++i) {
+        int32_t timeScale;
+        sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale);
+
+        const char *mime;
+        CHECK(format->findCString(kKeyMIMEType, &mime));
+
+        bool isAudio = !strncasecmp(mime, "audio/", 6);
+        bool isVideo = !strncasecmp(mime, "video/", 6);
+
+        TrackInfo info;
+        info.mTimeScale = timeScale;
+        info.mRTPTime = 0;
+        info.mNormalPlaytimeUs = 0ll;
+
+        if ((isAudio && mAudioTrack == NULL)
+                || (isVideo && mVideoTrack == NULL)) {
+            sp<AnotherPacketSource> source = new AnotherPacketSource(format);
+
+            if (isAudio) {
+                mAudioTrack = source;
+            } else {
+                mVideoTrack = source;
+            }
+
+            info.mSource = source;
+        }
+
+        mTracks.push(info);
+    }
+
+    mState = CONNECTED;
+}
+
+void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) {
+    status_t err;
+    CHECK(msg->findInt32("result", &err));
+    CHECK_NE(err, (status_t)OK);
+
+    mLooper->unregisterHandler(mHandler->id());
+    mHandler.clear();
+
+    mState = DISCONNECTED;
+    mFinalResult = err;
+
+    if (mDisconnectReplyID != 0) {
+        finishDisconnectIfPossible();
+    }
+}
+
+void NuPlayer::RTSPSource::finishDisconnectIfPossible() {
+    if (mState != DISCONNECTED) {
+        mHandler->disconnect();
+        return;
+    }
+
+    (new AMessage)->postReply(mDisconnectReplyID);
+    mDisconnectReplyID = 0;
+}
+
+}  // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
new file mode 100644
index 0000000..66eab72
--- /dev/null
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RTSP_SOURCE_H_
+
+#define RTSP_SOURCE_H_
+
+#include "NuPlayerSource.h"
+
+#include <media/stagefright/foundation/AHandlerReflector.h>
+
+namespace android {
+
+struct ALooper;
+struct AnotherPacketSource;
+struct MyHandler;
+
+struct NuPlayer::RTSPSource : public NuPlayer::Source {
+    RTSPSource(
+            const char *url,
+            const KeyedVector<String8, String8> *headers,
+            bool uidValid = false,
+            uid_t uid = 0);
+
+    virtual void start();
+    virtual void stop();
+
+    virtual status_t feedMoreTSData();
+
+    virtual sp<MetaData> getFormat(bool audio);
+    virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
+
+    virtual status_t getDuration(int64_t *durationUs);
+    virtual status_t seekTo(int64_t seekTimeUs);
+    virtual bool isSeekable();
+
+    void onMessageReceived(const sp<AMessage> &msg);
+
+protected:
+    virtual ~RTSPSource();
+
+private:
+    enum {
+        kWhatNotify          = 'noti',
+        kWhatDisconnect      = 'disc',
+    };
+
+    enum State {
+        DISCONNECTED,
+        CONNECTING,
+        CONNECTED,
+        SEEKING,
+    };
+
+    enum Flags {
+        // Don't log any URLs.
+        kFlagIncognito = 1,
+    };
+
+    struct TrackInfo {
+        sp<AnotherPacketSource> mSource;
+
+        int32_t mTimeScale;
+        uint32_t mRTPTime;
+        int64_t mNormalPlaytimeUs;
+    };
+
+    AString mURL;
+    KeyedVector<String8, String8> mExtraHeaders;
+    bool mUIDValid;
+    uid_t mUID;
+    uint32_t mFlags;
+    State mState;
+    status_t mFinalResult;
+    uint32_t mDisconnectReplyID;
+
+    sp<ALooper> mLooper;
+    sp<AHandlerReflector<RTSPSource> > mReflector;
+    sp<MyHandler> mHandler;
+
+    Vector<TrackInfo> mTracks;
+    sp<AnotherPacketSource> mAudioTrack;
+    sp<AnotherPacketSource> mVideoTrack;
+
+    sp<AnotherPacketSource> getSource(bool audio);
+
+    void onConnected();
+    void onDisconnected(const sp<AMessage> &msg);
+    void finishDisconnectIfPossible();
+
+    DISALLOW_EVIL_CONSTRUCTORS(RTSPSource);
+};
+
+}  // namespace android
+
+#endif  // RTSP_SOURCE_H_
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 9cb18de..d947760 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -681,6 +681,10 @@
     static const MimeToRole kMimeToRole[] = {
         { MEDIA_MIMETYPE_AUDIO_MPEG,
             "audio_decoder.mp3", "audio_encoder.mp3" },
+        { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I,
+            "audio_decoder.mp1", "audio_encoder.mp1" },
+        { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II,
+            "audio_decoder.mp2", "audio_encoder.mp2" },
         { MEDIA_MIMETYPE_AUDIO_AMR_NB,
             "audio_decoder.amrnb", "audio_encoder.amrnb" },
         { MEDIA_MIMETYPE_AUDIO_AMR_WB,
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 0b1a2af..0aeb515 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -58,7 +58,6 @@
         $(TOP)/frameworks/base/include/media/stagefright/openmax \
         $(TOP)/external/flac/include \
         $(TOP)/external/tremolo \
-        $(TOP)/frameworks/base/media/libstagefright/rtsp \
         $(TOP)/external/openssl/include \
 
 LOCAL_SHARED_LIBRARIES := \
@@ -88,7 +87,6 @@
         libvpx \
         libstagefright_mpeg2ts \
         libstagefright_httplive \
-        libstagefright_rtsp \
         libstagefright_id3 \
         libFLAC \
 
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 1165af5..1c7e58d 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -22,7 +22,6 @@
 
 #include <dlfcn.h>
 
-#include "include/ARTSPController.h"
 #include "include/AwesomePlayer.h"
 #include "include/DRMExtractor.h"
 #include "include/SoftwareRenderer.h"
@@ -53,7 +52,6 @@
 #include <gui/SurfaceTextureClient.h>
 #include <surfaceflinger/ISurfaceComposer.h>
 
-#include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
 
 #include <cutils/properties.h>
@@ -65,7 +63,6 @@
 
 static int64_t kLowWaterMarkUs = 2000000ll;  // 2secs
 static int64_t kHighWaterMarkUs = 5000000ll;  // 5secs
-static int64_t kHighWaterMarkRTSPUs = 4000000ll;  // 4secs
 static const size_t kLowWaterMarkBytes = 40000;
 static const size_t kHighWaterMarkBytes = 200000;
 
@@ -485,9 +482,6 @@
         if (mConnectingDataSource != NULL) {
             LOGI("interrupting the connection process");
             mConnectingDataSource->disconnect();
-        } else if (mConnectingRTSPController != NULL) {
-            LOGI("interrupting the connection process");
-            mConnectingRTSPController->disconnect();
         }
 
         if (mFlags & PREPARING_CONNECTED) {
@@ -534,11 +528,6 @@
 
     mVideoRenderer.clear();
 
-    if (mRTSPController != NULL) {
-        mRTSPController->disconnect();
-        mRTSPController.clear();
-    }
-
     if (mVideoSource != NULL) {
         shutdownVideoDecoder_l();
     }
@@ -612,10 +601,7 @@
 bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
     int64_t bitrate;
 
-    if (mRTSPController != NULL) {
-        *durationUs = mRTSPController->getQueueDurationUs(eos);
-        return true;
-    } else if (mCachedSource != NULL && getBitrate(&bitrate)) {
+    if (mCachedSource != NULL && getBitrate(&bitrate)) {
         status_t finalStatus;
         size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
         *durationUs = cachedDataRemaining * 8000000ll / bitrate;
@@ -751,9 +737,6 @@
         LOGV("cachedDurationUs = %.2f secs, eos=%d",
              cachedDurationUs / 1E6, eos);
 
-        int64_t highWaterMarkUs =
-            (mRTSPController != NULL) ? kHighWaterMarkRTSPUs : kHighWaterMarkUs;
-
         if ((mFlags & PLAYING) && !eos
                 && (cachedDurationUs < kLowWaterMarkUs)) {
             LOGI("cache is running low (%.2f secs) , pausing.",
@@ -763,7 +746,7 @@
             ensureCacheIsFetching_l();
             sendCacheStats();
             notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
-        } else if (eos || cachedDurationUs > highWaterMarkUs) {
+        } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
             if (mFlags & CACHE_UNDERRUN) {
                 LOGI("cache has filled up (%.2f secs), resuming.",
                      cachedDurationUs / 1E6);
@@ -1081,7 +1064,8 @@
 
     if (USE_SURFACE_ALLOC
             && !strncmp(component, "OMX.", 4)
-            && strncmp(component, "OMX.google.", 11)) {
+            && strncmp(component, "OMX.google.", 11)
+            && strcmp(component, "OMX.Nvidia.mpeg2v.decode")) {
         // Hardware decoders avoid the CPU color conversion by decoding
         // directly to ANativeBuffers, so we must use a renderer that
         // just pushes those buffers to the ANativeWindow.
@@ -1263,10 +1247,7 @@
 }
 
 status_t AwesomePlayer::getPosition(int64_t *positionUs) {
-    if (mRTSPController != NULL) {
-        *positionUs = mRTSPController->getNormalPlayTimeUs();
-    }
-    else if (mSeeking != NO_SEEK) {
+    if (mSeeking != NO_SEEK) {
         *positionUs = mSeekTimeUs;
     } else if (mVideoSource != NULL
             && (mAudioPlayer == NULL || !(mFlags & VIDEO_AT_EOS))) {
@@ -1316,25 +1297,7 @@
     }
 }
 
-// static
-void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) {
-    static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone();
-}
-
-void AwesomePlayer::onRTSPSeekDone() {
-    if (!mSeekNotificationSent) {
-        notifyListener_l(MEDIA_SEEK_COMPLETE);
-        mSeekNotificationSent = true;
-    }
-}
-
 status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
-    if (mRTSPController != NULL) {
-        mSeekNotificationSent = false;
-        mRTSPController->seekAsync(timeUs, OnRTSPSeekDoneWrapper, this);
-        return OK;
-    }
-
     if (mFlags & CACHE_UNDERRUN) {
         modifyFlags(CACHE_UNDERRUN, CLEAR);
         play_l();
@@ -1770,7 +1733,6 @@
         int64_t latenessUs = nowUs - timeUs;
 
         if (latenessUs > 500000ll
-                && mRTSPController == NULL
                 && mAudioPlayer != NULL
                 && mAudioPlayer->getMediaTimeMapping(
                     &realTimeUs, &mediaTimeUs)) {
@@ -2085,34 +2047,6 @@
                 return UNKNOWN_ERROR;
             }
         }
-    } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
-        if (mLooper == NULL) {
-            mLooper = new ALooper;
-            mLooper->setName("rtsp");
-            mLooper->start();
-        }
-        mRTSPController = new ARTSPController(mLooper);
-        mConnectingRTSPController = mRTSPController;
-
-        if (mUIDValid) {
-            mConnectingRTSPController->setUID(mUID);
-        }
-
-        mLock.unlock();
-        status_t err = mRTSPController->connect(mUri.string());
-        mLock.lock();
-
-        mConnectingRTSPController.clear();
-
-        LOGI("ARTSPController::connect returned %d", err);
-
-        if (err != OK) {
-            mRTSPController.clear();
-            return err;
-        }
-
-        sp<MediaExtractor> extractor = mRTSPController.get();
-        return setDataSource_l(extractor);
     } else {
         dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
     }
@@ -2224,7 +2158,7 @@
 
     modifyFlags(PREPARING_CONNECTED, SET);
 
-    if (isStreamingHTTP() || mRTSPController != NULL) {
+    if (isStreamingHTTP()) {
         postBufferingEvent_l();
     } else {
         finishAsyncPrepare_l();
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index c16b3b5..70523c1 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -20,6 +20,7 @@
 #include "include/MPEG4Extractor.h"
 #include "include/WAVExtractor.h"
 #include "include/OggExtractor.h"
+#include "include/MPEG2PSExtractor.h"
 #include "include/MPEG2TSExtractor.h"
 #include "include/NuCachedSource2.h"
 #include "include/HTTPBase.h"
@@ -113,6 +114,7 @@
     RegisterSniffer(SniffMP3);
     RegisterSniffer(SniffAAC);
     RegisterSniffer(SniffAVI);
+    RegisterSniffer(SniffMPEG2PS);
 
     char value[PROPERTY_VALUE_MAX];
     if (property_get("drm.service.enabled", value, NULL)
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 92e84c2..34e9cd7 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -25,11 +25,11 @@
 #include "include/VBRISeeker.h"
 #include "include/XINGSeeker.h"
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaSource.h>
@@ -289,9 +289,24 @@
     GetMPEGAudioFrameSize(
             header, &frame_size, &sample_rate, &num_channels, &bitrate);
 
+    unsigned layer = 4 - ((header >> 17) & 3);
+
     mMeta = new MetaData;
 
-    mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+    switch (layer) {
+        case 1:
+            mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
+            break;
+        case 2:
+            mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
+            break;
+        case 3:
+            mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+            break;
+        default:
+            TRESPASS();
+    }
+
     mMeta->setInt32(kKeySampleRate, sample_rate);
     mMeta->setInt32(kKeyBitRate, bitrate * 1000);
     mMeta->setInt32(kKeyChannelCount, num_channels);
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 01f1fba..444e823 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -30,6 +30,8 @@
 const char *MEDIA_MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
 const char *MEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
 const char *MEDIA_MIMETYPE_AUDIO_MPEG = "audio/mpeg";
+const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I = "audio/mpeg-L1";
+const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II = "audio/mpeg-L2";
 const char *MEDIA_MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
 const char *MEDIA_MIMETYPE_AUDIO_QCELP = "audio/qcelp";
 const char *MEDIA_MIMETYPE_AUDIO_VORBIS = "audio/vorbis";
@@ -45,6 +47,7 @@
 const char *MEDIA_MIMETYPE_CONTAINER_MATROSKA = "video/x-matroska";
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG2TS = "video/mp2ts";
 const char *MEDIA_MIMETYPE_CONTAINER_AVI = "video/avi";
+const char *MEDIA_MIMETYPE_CONTAINER_MPEG2PS = "video/mp2p";
 
 const char *MEDIA_MIMETYPE_CONTAINER_WVM = "video/wvm";
 
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index a8023df..2221268 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -24,6 +24,7 @@
 #include "include/MPEG4Extractor.h"
 #include "include/WAVExtractor.h"
 #include "include/OggExtractor.h"
+#include "include/MPEG2PSExtractor.h"
 #include "include/MPEG2TSExtractor.h"
 #include "include/DRMExtractor.h"
 #include "include/WVMExtractor.h"
@@ -115,6 +116,8 @@
         ret = new WVMExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
         ret = new AACExtractor(source);
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
+        ret = new MPEG2PSExtractor(source);
     }
 
     if (ret != NULL) {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 7c34257..86bd267 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -102,6 +102,7 @@
     { MEDIA_MIMETYPE_IMAGE_JPEG, "OMX.TI.JPEG.decode" },
 //    { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" },
     { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.google.mp3.decoder" },
+    { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II, "OMX.Nvidia.mp2.decoder" },
 //    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.decode" },
 //    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.Nvidia.amr.decoder" },
     { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.google.amrnb.decoder" },
@@ -1462,7 +1463,9 @@
       mOutputPortSettingsChangedPending(false),
       mLeftOverBuffer(NULL),
       mPaused(false),
-      mNativeWindow(!strncmp(componentName, "OMX.google.", 11)
+      mNativeWindow(
+              (!strncmp(componentName, "OMX.google.", 11)
+              || !strcmp(componentName, "OMX.Nvidia.mpeg2v.decode"))
                         ? NULL : nativeWindow) {
     mPortStatus[kPortIndexInput] = ENABLED;
     mPortStatus[kPortIndexOutput] = ENABLED;
@@ -1483,6 +1486,12 @@
     static const MimeToRole kMimeToRole[] = {
         { MEDIA_MIMETYPE_AUDIO_MPEG,
             "audio_decoder.mp3", "audio_encoder.mp3" },
+        { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I,
+            "audio_decoder.mp1", "audio_encoder.mp1" },
+        { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II,
+            "audio_decoder.mp2", "audio_encoder.mp2" },
+        { MEDIA_MIMETYPE_AUDIO_MPEG,
+            "audio_decoder.mp3", "audio_encoder.mp3" },
         { MEDIA_MIMETYPE_AUDIO_AMR_NB,
             "audio_decoder.amrnb", "audio_encoder.amrnb" },
         { MEDIA_MIMETYPE_AUDIO_AMR_WB,
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index 571e8be27..bb6e4cd 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -38,7 +38,7 @@
         ".mpeg", ".ogg", ".mid", ".smf", ".imy", ".wma", ".aac",
         ".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota",
         ".mkv", ".mka", ".webm", ".ts", ".fl", ".flac", ".mxmf",
-        ".avi",
+        ".avi", ".mpeg", ".mpg"
     };
     static const size_t kNumValidExtensions =
         sizeof(kValidExtensions) / sizeof(kValidExtensions[0]);
diff --git a/media/libstagefright/include/ARTSPController.h b/media/libstagefright/include/ARTSPController.h
deleted file mode 100644
index 2bd5be6..0000000
--- a/media/libstagefright/include/ARTSPController.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef A_RTSP_CONTROLLER_H_
-
-#define A_RTSP_CONTROLLER_H_
-
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AHandlerReflector.h>
-#include <media/stagefright/MediaExtractor.h>
-
-namespace android {
-
-struct ALooper;
-struct MyHandler;
-
-struct ARTSPController : public MediaExtractor {
-    ARTSPController(const sp<ALooper> &looper);
-
-    void setUID(uid_t uid);
-
-    status_t connect(const char *url);
-    void disconnect();
-
-    void seekAsync(int64_t timeUs, void (*seekDoneCb)(void *), void *cookie);
-
-    virtual size_t countTracks();
-    virtual sp<MediaSource> getTrack(size_t index);
-
-    virtual sp<MetaData> getTrackMetaData(
-            size_t index, uint32_t flags);
-
-    int64_t getNormalPlayTimeUs();
-    int64_t getQueueDurationUs(bool *eos);
-
-    void onMessageReceived(const sp<AMessage> &msg);
-
-    virtual uint32_t flags() const {
-        // Seeking 10secs forward or backward is a very expensive operation
-        // for rtsp, so let's not enable that.
-        // The user can always use the seek bar.
-
-        return CAN_PAUSE | CAN_SEEK;
-    }
-
-protected:
-    virtual ~ARTSPController();
-
-private:
-    enum {
-        kWhatConnectDone    = 'cdon',
-        kWhatDisconnectDone = 'ddon',
-        kWhatSeekDone       = 'sdon',
-    };
-
-    enum State {
-        DISCONNECTED,
-        CONNECTED,
-        CONNECTING,
-    };
-
-    Mutex mLock;
-    Condition mCondition;
-
-    State mState;
-    status_t mConnectionResult;
-
-    sp<ALooper> mLooper;
-    sp<MyHandler> mHandler;
-    sp<AHandlerReflector<ARTSPController> > mReflector;
-
-    bool mUIDValid;
-    uid_t mUID;
-
-    void (*mSeekDoneCb)(void *);
-    void *mSeekDoneCookie;
-    int64_t mLastSeekCompletedTimeUs;
-
-    DISALLOW_EVIL_CONSTRUCTORS(ARTSPController);
-};
-
-}  // namespace android
-
-#endif  // A_RTSP_CONTROLLER_H_
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 8e73121..7d6bcad 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -38,9 +38,6 @@
 struct NuCachedSource2;
 struct ISurfaceTexture;
 
-struct ALooper;
-struct ARTSPController;
-
 class DrmManagerClinet;
 class DecryptHandle;
 
@@ -233,10 +230,6 @@
     sp<HTTPBase> mConnectingDataSource;
     sp<NuCachedSource2> mCachedSource;
 
-    sp<ALooper> mLooper;
-    sp<ARTSPController> mRTSPController;
-    sp<ARTSPController> mConnectingRTSPController;
-
     DrmManagerClient *mDrmManagerClient;
     sp<DecryptHandle> mDecryptHandle;
 
@@ -287,9 +280,6 @@
 
     static bool ContinuePreparation(void *cookie);
 
-    static void OnRTSPSeekDoneWrapper(void *cookie);
-    void onRTSPSeekDone();
-
     bool getBitrate(int64_t *bitrate);
 
     void finishSeekIfNecessary(int64_t videoTimeUs);
diff --git a/media/libstagefright/include/MPEG2PSExtractor.h b/media/libstagefright/include/MPEG2PSExtractor.h
new file mode 100644
index 0000000..fb76564
--- /dev/null
+++ b/media/libstagefright/include/MPEG2PSExtractor.h
@@ -0,0 +1,80 @@
+/*
+ * 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 MPEG2_PS_EXTRACTOR_H_
+
+#define MPEG2_PS_EXTRACTOR_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <utils/threads.h>
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+struct ABuffer;
+struct AMessage;
+struct Track;
+struct String8;
+
+struct MPEG2PSExtractor : public MediaExtractor {
+    MPEG2PSExtractor(const sp<DataSource> &source);
+
+    virtual size_t countTracks();
+    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
+
+    virtual sp<MetaData> getMetaData();
+
+    virtual uint32_t flags() const;
+
+protected:
+    virtual ~MPEG2PSExtractor();
+
+private:
+    struct Track;
+    struct WrappedTrack;
+
+    mutable Mutex mLock;
+    sp<DataSource> mDataSource;
+
+    off64_t mOffset;
+    status_t mFinalResult;
+    sp<ABuffer> mBuffer;
+    KeyedVector<unsigned, sp<Track> > mTracks;
+    bool mScanning;
+
+    bool mProgramStreamMapValid;
+    KeyedVector<unsigned, unsigned> mStreamTypeByESID;
+
+    status_t feedMore();
+
+    status_t dequeueChunk();
+    ssize_t dequeuePack();
+    ssize_t dequeueSystemHeader();
+    ssize_t dequeuePES();
+
+    DISALLOW_EVIL_CONSTRUCTORS(MPEG2PSExtractor);
+};
+
+bool SniffMPEG2PS(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *);
+
+}  // namespace android
+
+#endif  // MPEG2_PS_EXTRACTOR_H_
+
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 388cb54..878e534 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -64,12 +64,9 @@
 
     bool PTSTimeDeltaEstablished();
 
-protected:
-    virtual ~ATSParser();
-
-private:
     enum {
         // From ISO/IEC 13818-1: 2000 (E), Table 2-29
+        STREAMTYPE_RESERVED             = 0x00,
         STREAMTYPE_MPEG1_VIDEO          = 0x01,
         STREAMTYPE_MPEG2_VIDEO          = 0x02,
         STREAMTYPE_MPEG1_AUDIO          = 0x03,
@@ -79,6 +76,10 @@
         STREAMTYPE_H264                 = 0x1b,
     };
 
+protected:
+    virtual ~ATSParser();
+
+private:
     struct Program;
     struct Stream;
 
diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk
index 4a30416..578c669 100644
--- a/media/libstagefright/mpeg2ts/Android.mk
+++ b/media/libstagefright/mpeg2ts/Android.mk
@@ -6,6 +6,7 @@
         AnotherPacketSource.cpp   \
         ATSParser.cpp             \
         ESQueue.cpp               \
+        MPEG2PSExtractor.cpp      \
         MPEG2TSExtractor.cpp      \
 
 LOCAL_C_INCLUDES:= \
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index a56da36..b9a4826 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -585,6 +585,8 @@
         return NULL;
     }
 
+    unsigned layer = 4 - ((header >> 17) & 3);
+
     sp<ABuffer> accessUnit = new ABuffer(frameSize);
     memcpy(accessUnit->data(), data, frameSize);
 
@@ -601,7 +603,24 @@
 
     if (mFormat == NULL) {
         mFormat = new MetaData;
-        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+
+        switch (layer) {
+            case 1:
+                mFormat->setCString(
+                        kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
+                break;
+            case 2:
+                mFormat->setCString(
+                        kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
+                break;
+            case 3:
+                mFormat->setCString(
+                        kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+                break;
+            default:
+                TRESPASS();
+        }
+
         mFormat->setInt32(kKeySampleRate, samplingRate);
         mFormat->setInt32(kKeyChannelCount, numChannels);
     }
diff --git a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
new file mode 100644
index 0000000..f55be6e
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
@@ -0,0 +1,715 @@
+/*
+ * 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 "MPEG2PSExtractor"
+#include <utils/Log.h>
+
+#include "include/MPEG2PSExtractor.h"
+
+#include "AnotherPacketSource.h"
+#include "ESQueue.h"
+
+#include <media/stagefright/foundation/ABitReader.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+#include <utils/String8.h>
+
+namespace android {
+
+struct MPEG2PSExtractor::Track : public MediaSource {
+    Track(MPEG2PSExtractor *extractor,
+          unsigned stream_id, unsigned stream_type);
+
+    virtual status_t start(MetaData *params);
+    virtual status_t stop();
+    virtual sp<MetaData> getFormat();
+
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options);
+
+protected:
+    virtual ~Track();
+
+private:
+    friend struct MPEG2PSExtractor;
+
+    MPEG2PSExtractor *mExtractor;
+
+    unsigned mStreamID;
+    unsigned mStreamType;
+    ElementaryStreamQueue *mQueue;
+    sp<AnotherPacketSource> mSource;
+
+    status_t appendPESData(
+            unsigned PTS_DTS_flags,
+            uint64_t PTS, uint64_t DTS,
+            const uint8_t *data, size_t size);
+
+    DISALLOW_EVIL_CONSTRUCTORS(Track);
+};
+
+struct MPEG2PSExtractor::WrappedTrack : public MediaSource {
+    WrappedTrack(const sp<MPEG2PSExtractor> &extractor, const sp<Track> &track);
+
+    virtual status_t start(MetaData *params);
+    virtual status_t stop();
+    virtual sp<MetaData> getFormat();
+
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options);
+
+protected:
+    virtual ~WrappedTrack();
+
+private:
+    sp<MPEG2PSExtractor> mExtractor;
+    sp<MPEG2PSExtractor::Track> mTrack;
+
+    DISALLOW_EVIL_CONSTRUCTORS(WrappedTrack);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+MPEG2PSExtractor::MPEG2PSExtractor(const sp<DataSource> &source)
+    : mDataSource(source),
+      mOffset(0),
+      mFinalResult(OK),
+      mBuffer(new ABuffer(0)),
+      mScanning(true),
+      mProgramStreamMapValid(false) {
+    for (size_t i = 0; i < 500; ++i) {
+        if (feedMore() != OK) {
+            break;
+        }
+    }
+
+    // Remove all tracks that were unable to determine their format.
+    for (size_t i = mTracks.size(); i-- > 0;) {
+        if (mTracks.valueAt(i)->getFormat() == NULL) {
+            mTracks.removeItemsAt(i);
+        }
+    }
+
+    mScanning = false;
+}
+
+MPEG2PSExtractor::~MPEG2PSExtractor() {
+}
+
+size_t MPEG2PSExtractor::countTracks() {
+    return mTracks.size();
+}
+
+sp<MediaSource> MPEG2PSExtractor::getTrack(size_t index) {
+    if (index >= mTracks.size()) {
+        return NULL;
+    }
+
+    return new WrappedTrack(this, mTracks.valueAt(index));
+}
+
+sp<MetaData> MPEG2PSExtractor::getTrackMetaData(size_t index, uint32_t flags) {
+    if (index >= mTracks.size()) {
+        return NULL;
+    }
+
+    return mTracks.valueAt(index)->getFormat();
+}
+
+sp<MetaData> MPEG2PSExtractor::getMetaData() {
+    sp<MetaData> meta = new MetaData;
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG2PS);
+
+    return meta;
+}
+
+uint32_t MPEG2PSExtractor::flags() const {
+    return CAN_PAUSE;
+}
+
+status_t MPEG2PSExtractor::feedMore() {
+    Mutex::Autolock autoLock(mLock);
+
+    // How much data we're reading at a time
+    static const size_t kChunkSize = 8192;
+
+    for (;;) {
+        status_t err = dequeueChunk();
+
+        if (err == -EAGAIN && mFinalResult == OK) {
+            memmove(mBuffer->base(), mBuffer->data(), mBuffer->size());
+            mBuffer->setRange(0, mBuffer->size());
+
+            if (mBuffer->size() + kChunkSize > mBuffer->capacity()) {
+                size_t newCapacity = mBuffer->capacity() + kChunkSize;
+                sp<ABuffer> newBuffer = new ABuffer(newCapacity);
+                memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size());
+                newBuffer->setRange(0, mBuffer->size());
+                mBuffer = newBuffer;
+            }
+
+            ssize_t n = mDataSource->readAt(
+                    mOffset, mBuffer->data() + mBuffer->size(), kChunkSize);
+
+            if (n < (ssize_t)kChunkSize) {
+                mFinalResult = (n < 0) ? (status_t)n : ERROR_END_OF_STREAM;
+                return mFinalResult;
+            }
+
+            mBuffer->setRange(mBuffer->offset(), mBuffer->size() + n);
+            mOffset += n;
+        } else if (err != OK) {
+            mFinalResult = err;
+            return err;
+        } else {
+            return OK;
+        }
+    }
+}
+
+status_t MPEG2PSExtractor::dequeueChunk() {
+    if (mBuffer->size() < 4) {
+        return -EAGAIN;
+    }
+
+    if (memcmp("\x00\x00\x01", mBuffer->data(), 3)) {
+        return ERROR_MALFORMED;
+    }
+
+    unsigned chunkType = mBuffer->data()[3];
+
+    ssize_t res;
+
+    switch (chunkType) {
+        case 0xba:
+        {
+            res = dequeuePack();
+            break;
+        }
+
+        case 0xbb:
+        {
+            res = dequeueSystemHeader();
+            break;
+        }
+
+        default:
+        {
+            res = dequeuePES();
+            break;
+        }
+    }
+
+    if (res > 0) {
+        if (mBuffer->size() < (size_t)res) {
+            return -EAGAIN;
+        }
+
+        mBuffer->setRange(mBuffer->offset() + res, mBuffer->size() - res);
+        res = OK;
+    }
+
+    return res;
+}
+
+ssize_t MPEG2PSExtractor::dequeuePack() {
+    // 32 + 2 + 3 + 1 + 15 + 1 + 15+ 1 + 9 + 1 + 22 + 1 + 1 | +5
+
+    if (mBuffer->size() < 14) {
+        return -EAGAIN;
+    }
+
+    unsigned pack_stuffing_length = mBuffer->data()[13] & 7;
+
+    return pack_stuffing_length + 14;
+}
+
+ssize_t MPEG2PSExtractor::dequeueSystemHeader() {
+    if (mBuffer->size() < 6) {
+        return -EAGAIN;
+    }
+
+    unsigned header_length = U16_AT(mBuffer->data() + 4);
+
+    return header_length + 6;
+}
+
+ssize_t MPEG2PSExtractor::dequeuePES() {
+    if (mBuffer->size() < 6) {
+        return -EAGAIN;
+    }
+
+    unsigned PES_packet_length = U16_AT(mBuffer->data() + 4);
+    CHECK_NE(PES_packet_length, 0u);
+
+    size_t n = PES_packet_length + 6;
+
+    if (mBuffer->size() < n) {
+        return -EAGAIN;
+    }
+
+    ABitReader br(mBuffer->data(), n);
+
+    unsigned packet_startcode_prefix = br.getBits(24);
+
+    LOGV("packet_startcode_prefix = 0x%08x", packet_startcode_prefix);
+
+    if (packet_startcode_prefix != 1) {
+        LOGV("Supposedly payload_unit_start=1 unit does not start "
+             "with startcode.");
+
+        return ERROR_MALFORMED;
+    }
+
+    CHECK_EQ(packet_startcode_prefix, 0x000001u);
+
+    unsigned stream_id = br.getBits(8);
+    LOGV("stream_id = 0x%02x", stream_id);
+
+    /* unsigned PES_packet_length = */br.getBits(16);
+
+    if (stream_id == 0xbc) {
+        // program_stream_map
+
+        if (!mScanning) {
+            return n;
+        }
+
+        mStreamTypeByESID.clear();
+
+        /* unsigned current_next_indicator = */br.getBits(1);
+        /* unsigned reserved = */br.getBits(2);
+        /* unsigned program_stream_map_version = */br.getBits(5);
+        /* unsigned reserved = */br.getBits(7);
+        /* unsigned marker_bit = */br.getBits(1);
+        unsigned program_stream_info_length = br.getBits(16);
+
+        size_t offset = 0;
+        while (offset < program_stream_info_length) {
+            if (offset + 2 > program_stream_info_length) {
+                return ERROR_MALFORMED;
+            }
+
+            unsigned descriptor_tag = br.getBits(8);
+            unsigned descriptor_length = br.getBits(8);
+
+            LOGI("found descriptor tag 0x%02x of length %u",
+                 descriptor_tag, descriptor_length);
+
+            if (offset + 2 + descriptor_length > program_stream_info_length) {
+                return ERROR_MALFORMED;
+            }
+
+            br.skipBits(8 * descriptor_length);
+
+            offset += 2 + descriptor_length;
+        }
+
+        unsigned elementary_stream_map_length = br.getBits(16);
+
+        offset = 0;
+        while (offset < elementary_stream_map_length) {
+            if (offset + 4 > elementary_stream_map_length) {
+                return ERROR_MALFORMED;
+            }
+
+            unsigned stream_type = br.getBits(8);
+            unsigned elementary_stream_id = br.getBits(8);
+
+            LOGI("elementary stream id 0x%02x has stream type 0x%02x",
+                 elementary_stream_id, stream_type);
+
+            mStreamTypeByESID.add(elementary_stream_id, stream_type);
+
+            unsigned elementary_stream_info_length = br.getBits(16);
+
+            if (offset + 4 + elementary_stream_info_length
+                    > elementary_stream_map_length) {
+                return ERROR_MALFORMED;
+            }
+
+            offset += 4 + elementary_stream_info_length;
+        }
+
+        /* unsigned CRC32 = */br.getBits(32);
+
+        mProgramStreamMapValid = true;
+    } else if (stream_id != 0xbe  // padding_stream
+            && stream_id != 0xbf  // private_stream_2
+            && stream_id != 0xf0  // ECM
+            && stream_id != 0xf1  // EMM
+            && stream_id != 0xff  // program_stream_directory
+            && stream_id != 0xf2  // DSMCC
+            && stream_id != 0xf8) {  // H.222.1 type E
+        CHECK_EQ(br.getBits(2), 2u);
+
+        /* unsigned PES_scrambling_control = */br.getBits(2);
+        /* unsigned PES_priority = */br.getBits(1);
+        /* unsigned data_alignment_indicator = */br.getBits(1);
+        /* unsigned copyright = */br.getBits(1);
+        /* unsigned original_or_copy = */br.getBits(1);
+
+        unsigned PTS_DTS_flags = br.getBits(2);
+        LOGV("PTS_DTS_flags = %u", PTS_DTS_flags);
+
+        unsigned ESCR_flag = br.getBits(1);
+        LOGV("ESCR_flag = %u", ESCR_flag);
+
+        unsigned ES_rate_flag = br.getBits(1);
+        LOGV("ES_rate_flag = %u", ES_rate_flag);
+
+        unsigned DSM_trick_mode_flag = br.getBits(1);
+        LOGV("DSM_trick_mode_flag = %u", DSM_trick_mode_flag);
+
+        unsigned additional_copy_info_flag = br.getBits(1);
+        LOGV("additional_copy_info_flag = %u", additional_copy_info_flag);
+
+        /* unsigned PES_CRC_flag = */br.getBits(1);
+        /* PES_extension_flag = */br.getBits(1);
+
+        unsigned PES_header_data_length = br.getBits(8);
+        LOGV("PES_header_data_length = %u", PES_header_data_length);
+
+        unsigned optional_bytes_remaining = PES_header_data_length;
+
+        uint64_t PTS = 0, DTS = 0;
+
+        if (PTS_DTS_flags == 2 || PTS_DTS_flags == 3) {
+            CHECK_GE(optional_bytes_remaining, 5u);
+
+            CHECK_EQ(br.getBits(4), PTS_DTS_flags);
+
+            PTS = ((uint64_t)br.getBits(3)) << 30;
+            CHECK_EQ(br.getBits(1), 1u);
+            PTS |= ((uint64_t)br.getBits(15)) << 15;
+            CHECK_EQ(br.getBits(1), 1u);
+            PTS |= br.getBits(15);
+            CHECK_EQ(br.getBits(1), 1u);
+
+            LOGV("PTS = %llu", PTS);
+            // LOGI("PTS = %.2f secs", PTS / 90000.0f);
+
+            optional_bytes_remaining -= 5;
+
+            if (PTS_DTS_flags == 3) {
+                CHECK_GE(optional_bytes_remaining, 5u);
+
+                CHECK_EQ(br.getBits(4), 1u);
+
+                DTS = ((uint64_t)br.getBits(3)) << 30;
+                CHECK_EQ(br.getBits(1), 1u);
+                DTS |= ((uint64_t)br.getBits(15)) << 15;
+                CHECK_EQ(br.getBits(1), 1u);
+                DTS |= br.getBits(15);
+                CHECK_EQ(br.getBits(1), 1u);
+
+                LOGV("DTS = %llu", DTS);
+
+                optional_bytes_remaining -= 5;
+            }
+        }
+
+        if (ESCR_flag) {
+            CHECK_GE(optional_bytes_remaining, 6u);
+
+            br.getBits(2);
+
+            uint64_t ESCR = ((uint64_t)br.getBits(3)) << 30;
+            CHECK_EQ(br.getBits(1), 1u);
+            ESCR |= ((uint64_t)br.getBits(15)) << 15;
+            CHECK_EQ(br.getBits(1), 1u);
+            ESCR |= br.getBits(15);
+            CHECK_EQ(br.getBits(1), 1u);
+
+            LOGV("ESCR = %llu", ESCR);
+            /* unsigned ESCR_extension = */br.getBits(9);
+
+            CHECK_EQ(br.getBits(1), 1u);
+
+            optional_bytes_remaining -= 6;
+        }
+
+        if (ES_rate_flag) {
+            CHECK_GE(optional_bytes_remaining, 3u);
+
+            CHECK_EQ(br.getBits(1), 1u);
+            /* unsigned ES_rate = */br.getBits(22);
+            CHECK_EQ(br.getBits(1), 1u);
+
+            optional_bytes_remaining -= 3;
+        }
+
+        br.skipBits(optional_bytes_remaining * 8);
+
+        // ES data follows.
+
+        CHECK_GE(PES_packet_length, PES_header_data_length + 3);
+
+        unsigned dataLength =
+            PES_packet_length - 3 - PES_header_data_length;
+
+        if (br.numBitsLeft() < dataLength * 8) {
+            LOGE("PES packet does not carry enough data to contain "
+                 "payload. (numBitsLeft = %d, required = %d)",
+                 br.numBitsLeft(), dataLength * 8);
+
+            return ERROR_MALFORMED;
+        }
+
+        CHECK_GE(br.numBitsLeft(), dataLength * 8);
+
+        ssize_t index = mTracks.indexOfKey(stream_id);
+        if (index < 0 && mScanning) {
+            unsigned streamType;
+
+            ssize_t streamTypeIndex;
+            if (mProgramStreamMapValid
+                    && (streamTypeIndex =
+                            mStreamTypeByESID.indexOfKey(stream_id)) >= 0) {
+                streamType = mStreamTypeByESID.valueAt(streamTypeIndex);
+            } else if ((stream_id & ~0x1f) == 0xc0) {
+                // ISO/IEC 13818-3 or ISO/IEC 11172-3 or ISO/IEC 13818-7
+                // or ISO/IEC 14496-3 audio
+                streamType = ATSParser::STREAMTYPE_MPEG2_AUDIO;
+            } else if ((stream_id & ~0x0f) == 0xe0) {
+                // ISO/IEC 13818-2 or ISO/IEC 11172-2 or ISO/IEC 14496-2 video
+                streamType = ATSParser::STREAMTYPE_MPEG2_VIDEO;
+            } else {
+                streamType = ATSParser::STREAMTYPE_RESERVED;
+            }
+
+            index = mTracks.add(
+                    stream_id, new Track(this, stream_id, streamType));
+        }
+
+        status_t err = OK;
+
+        if (index >= 0) {
+            err =
+                mTracks.editValueAt(index)->appendPESData(
+                    PTS_DTS_flags, PTS, DTS, br.data(), dataLength);
+        }
+
+        br.skipBits(dataLength * 8);
+
+        if (err != OK) {
+            return err;
+        }
+    } else if (stream_id == 0xbe) {  // padding_stream
+        CHECK_NE(PES_packet_length, 0u);
+        br.skipBits(PES_packet_length * 8);
+    } else {
+        CHECK_NE(PES_packet_length, 0u);
+        br.skipBits(PES_packet_length * 8);
+    }
+
+    return n;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MPEG2PSExtractor::Track::Track(
+        MPEG2PSExtractor *extractor, unsigned stream_id, unsigned stream_type)
+    : mExtractor(extractor),
+      mStreamID(stream_id),
+      mStreamType(stream_type),
+      mQueue(NULL) {
+    bool supported = true;
+    ElementaryStreamQueue::Mode mode;
+
+    switch (mStreamType) {
+        case ATSParser::STREAMTYPE_H264:
+            mode = ElementaryStreamQueue::H264;
+            break;
+        case ATSParser::STREAMTYPE_MPEG2_AUDIO_ATDS:
+            mode = ElementaryStreamQueue::AAC;
+            break;
+        case ATSParser::STREAMTYPE_MPEG1_AUDIO:
+        case ATSParser::STREAMTYPE_MPEG2_AUDIO:
+            mode = ElementaryStreamQueue::MPEG_AUDIO;
+            break;
+
+        case ATSParser::STREAMTYPE_MPEG1_VIDEO:
+        case ATSParser::STREAMTYPE_MPEG2_VIDEO:
+            mode = ElementaryStreamQueue::MPEG_VIDEO;
+            break;
+
+        case ATSParser::STREAMTYPE_MPEG4_VIDEO:
+            mode = ElementaryStreamQueue::MPEG4_VIDEO;
+            break;
+
+        default:
+            supported = false;
+            break;
+    }
+
+    if (supported) {
+        mQueue = new ElementaryStreamQueue(mode);
+    } else {
+        LOGI("unsupported stream ID 0x%02x", stream_id);
+    }
+}
+
+MPEG2PSExtractor::Track::~Track() {
+    delete mQueue;
+    mQueue = NULL;
+}
+
+status_t MPEG2PSExtractor::Track::start(MetaData *params) {
+    if (mSource == NULL) {
+        return NO_INIT;
+    }
+
+    return mSource->start(params);
+}
+
+status_t MPEG2PSExtractor::Track::stop() {
+    if (mSource == NULL) {
+        return NO_INIT;
+    }
+
+    return mSource->stop();
+}
+
+sp<MetaData> MPEG2PSExtractor::Track::getFormat() {
+    if (mSource == NULL) {
+        return NULL;
+    }
+
+    return mSource->getFormat();
+}
+
+status_t MPEG2PSExtractor::Track::read(
+        MediaBuffer **buffer, const ReadOptions *options) {
+    if (mSource == NULL) {
+        return NO_INIT;
+    }
+
+    status_t finalResult;
+    while (!mSource->hasBufferAvailable(&finalResult)) {
+        if (finalResult != OK) {
+            return ERROR_END_OF_STREAM;
+        }
+
+        status_t err = mExtractor->feedMore();
+
+        if (err != OK) {
+            mSource->signalEOS(err);
+        }
+    }
+
+    return mSource->read(buffer, options);
+}
+
+status_t MPEG2PSExtractor::Track::appendPESData(
+        unsigned PTS_DTS_flags,
+        uint64_t PTS, uint64_t DTS,
+        const uint8_t *data, size_t size) {
+    if (mQueue == NULL) {
+        return OK;
+    }
+
+    int64_t timeUs;
+    if (PTS_DTS_flags == 2 || PTS_DTS_flags == 3) {
+        timeUs = (PTS * 100) / 9;
+    } else {
+        timeUs = 0;
+    }
+
+    status_t err = mQueue->appendData(data, size, timeUs);
+
+    if (err != OK) {
+        return err;
+    }
+
+    sp<ABuffer> accessUnit;
+    while ((accessUnit = mQueue->dequeueAccessUnit()) != NULL) {
+        if (mSource == NULL) {
+            sp<MetaData> meta = mQueue->getFormat();
+
+            if (meta != NULL) {
+                LOGV("Stream ID 0x%02x now has data.", mStreamID);
+
+                mSource = new AnotherPacketSource(meta);
+                mSource->queueAccessUnit(accessUnit);
+            }
+        } else if (mQueue->getFormat() != NULL) {
+            mSource->queueAccessUnit(accessUnit);
+        }
+    }
+
+    return OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MPEG2PSExtractor::WrappedTrack::WrappedTrack(
+        const sp<MPEG2PSExtractor> &extractor, const sp<Track> &track)
+    : mExtractor(extractor),
+      mTrack(track) {
+}
+
+MPEG2PSExtractor::WrappedTrack::~WrappedTrack() {
+}
+
+status_t MPEG2PSExtractor::WrappedTrack::start(MetaData *params) {
+    return mTrack->start(params);
+}
+
+status_t MPEG2PSExtractor::WrappedTrack::stop() {
+    return mTrack->stop();
+}
+
+sp<MetaData> MPEG2PSExtractor::WrappedTrack::getFormat() {
+    return mTrack->getFormat();
+}
+
+status_t MPEG2PSExtractor::WrappedTrack::read(
+        MediaBuffer **buffer, const ReadOptions *options) {
+    return mTrack->read(buffer, options);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool SniffMPEG2PS(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *) {
+    uint8_t header[5];
+    if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+        return false;
+    }
+
+    if (memcmp("\x00\x00\x01\xba", header, 4) || (header[4] >> 6) != 1) {
+        return false;
+    }
+
+    *confidence = 0.25f;  // Slightly larger than .mp3 extractor's confidence
+
+    mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2PS);
+
+    return true;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 4ecb92f..3f4cdb5 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -34,8 +34,8 @@
 #include <media/stagefright/foundation/AString.h>
 #include <media/stagefright/foundation/base64.h>
 #include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/Vector.h>
 
@@ -402,43 +402,15 @@
     return csd;
 }
 
-static bool GetClockRate(const AString &desc, uint32_t *clockRate) {
-    ssize_t slashPos = desc.find("/");
-    if (slashPos < 0) {
-        return false;
-    }
-
-    const char *s = desc.c_str() + slashPos + 1;
-
-    char *end;
-    unsigned long x = strtoul(s, &end, 10);
-
-    if (end == s || (*end != '\0' && *end != '/')) {
-        return false;
-    }
-
-    *clockRate = x;
-
-    return true;
-}
-
 APacketSource::APacketSource(
         const sp<ASessionDescription> &sessionDesc, size_t index)
     : mInitCheck(NO_INIT),
-      mFormat(new MetaData),
-      mEOSResult(OK),
-      mIsAVC(false),
-      mScanForIDR(true),
-      mRTPTimeBase(0),
-      mNormalPlayTimeBaseUs(0),
-      mLastNormalPlayTimeUs(0) {
+      mFormat(new MetaData) {
     unsigned long PT;
     AString desc;
     AString params;
     sessionDesc->getFormatType(index, &PT, &desc, &params);
 
-    CHECK(GetClockRate(desc, &mClockRate));
-
     int64_t durationUs;
     if (sessionDesc->getDurationUs(&durationUs)) {
         mFormat->setInt64(kKeyDuration, durationUs);
@@ -448,8 +420,6 @@
 
     mInitCheck = OK;
     if (!strncmp(desc.c_str(), "H264/", 5)) {
-        mIsAVC = true;
-
         mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
 
         int32_t width, height;
@@ -602,137 +572,8 @@
     return mInitCheck;
 }
 
-status_t APacketSource::start(MetaData *params) {
-    return OK;
-}
-
-status_t APacketSource::stop() {
-    return OK;
-}
-
 sp<MetaData> APacketSource::getFormat() {
     return mFormat;
 }
 
-status_t APacketSource::read(
-        MediaBuffer **out, const ReadOptions *) {
-    *out = NULL;
-
-    Mutex::Autolock autoLock(mLock);
-    while (mEOSResult == OK && mBuffers.empty()) {
-        mCondition.wait(mLock);
-    }
-
-    if (!mBuffers.empty()) {
-        const sp<ABuffer> buffer = *mBuffers.begin();
-
-        updateNormalPlayTime_l(buffer);
-
-        int64_t timeUs;
-        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
-
-        MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
-        mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
-
-        *out = mediaBuffer;
-
-        mBuffers.erase(mBuffers.begin());
-        return OK;
-    }
-
-    return mEOSResult;
-}
-
-void APacketSource::updateNormalPlayTime_l(const sp<ABuffer> &buffer) {
-    uint32_t rtpTime;
-    CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
-
-    mLastNormalPlayTimeUs =
-        (((double)rtpTime - (double)mRTPTimeBase) / mClockRate)
-            * 1000000ll
-            + mNormalPlayTimeBaseUs;
-}
-
-void APacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
-    int32_t damaged;
-    if (buffer->meta()->findInt32("damaged", &damaged) && damaged) {
-        LOGV("discarding damaged AU");
-        return;
-    }
-
-    if (mScanForIDR && mIsAVC) {
-        // This pretty piece of code ensures that the first access unit
-        // fed to the decoder after stream-start or seek is guaranteed to
-        // be an IDR frame. This is to workaround limitations of a certain
-        // hardware h.264 decoder that requires this to be the case.
-
-        if (!IsIDR(buffer)) {
-            LOGV("skipping AU while scanning for next IDR frame.");
-            return;
-        }
-
-        mScanForIDR = false;
-    }
-
-    Mutex::Autolock autoLock(mLock);
-    mBuffers.push_back(buffer);
-    mCondition.signal();
-}
-
-void APacketSource::signalEOS(status_t result) {
-    CHECK(result != OK);
-
-    Mutex::Autolock autoLock(mLock);
-    mEOSResult = result;
-    mCondition.signal();
-}
-
-void APacketSource::flushQueue() {
-    Mutex::Autolock autoLock(mLock);
-    mBuffers.clear();
-
-    mScanForIDR = true;
-}
-
-int64_t APacketSource::getNormalPlayTimeUs() {
-    Mutex::Autolock autoLock(mLock);
-    return mLastNormalPlayTimeUs;
-}
-
-void APacketSource::setNormalPlayTimeMapping(
-        uint32_t rtpTime, int64_t normalPlayTimeUs) {
-    Mutex::Autolock autoLock(mLock);
-
-    mRTPTimeBase = rtpTime;
-    mNormalPlayTimeBaseUs = normalPlayTimeUs;
-}
-
-int64_t APacketSource::getQueueDurationUs(bool *eos) {
-    Mutex::Autolock autoLock(mLock);
-
-    *eos = (mEOSResult != OK);
-
-    if (mBuffers.size() < 2) {
-        return 0;
-    }
-
-    const sp<ABuffer> first = *mBuffers.begin();
-    const sp<ABuffer> last = *--mBuffers.end();
-
-    int64_t firstTimeUs;
-    CHECK(first->meta()->findInt64("timeUs", &firstTimeUs));
-
-    int64_t lastTimeUs;
-    CHECK(last->meta()->findInt64("timeUs", &lastTimeUs));
-
-    if (lastTimeUs < firstTimeUs) {
-        LOGE("Huh? Time moving backwards? %lld > %lld",
-             firstTimeUs, lastTimeUs);
-
-        return 0;
-    }
-
-    return lastTimeUs - firstTimeUs;
-}
-
 }  // namespace android
diff --git a/media/libstagefright/rtsp/APacketSource.h b/media/libstagefright/rtsp/APacketSource.h
index 7a77fc6..530e537 100644
--- a/media/libstagefright/rtsp/APacketSource.h
+++ b/media/libstagefright/rtsp/APacketSource.h
@@ -19,63 +19,27 @@
 #define A_PACKET_SOURCE_H_
 
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaSource.h>
-#include <utils/threads.h>
-#include <utils/List.h>
+#include <media/stagefright/MetaData.h>
+#include <utils/RefBase.h>
 
 namespace android {
 
-struct ABuffer;
 struct ASessionDescription;
 
-struct APacketSource : public MediaSource {
+struct APacketSource : public RefBase {
     APacketSource(const sp<ASessionDescription> &sessionDesc, size_t index);
 
     status_t initCheck() const;
 
-    virtual status_t start(MetaData *params = NULL);
-    virtual status_t stop();
     virtual sp<MetaData> getFormat();
 
-    virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options = NULL);
-
-    void queueAccessUnit(const sp<ABuffer> &buffer);
-    void signalEOS(status_t result);
-
-    void flushQueue();
-
-    int64_t getNormalPlayTimeUs();
-
-    void setNormalPlayTimeMapping(
-            uint32_t rtpTime, int64_t normalPlayTimeUs);
-
-    int64_t getQueueDurationUs(bool *eos);
-
 protected:
     virtual ~APacketSource();
 
 private:
     status_t mInitCheck;
 
-    Mutex mLock;
-    Condition mCondition;
-
     sp<MetaData> mFormat;
-    List<sp<ABuffer> > mBuffers;
-    status_t mEOSResult;
-
-    bool mIsAVC;
-    bool mScanForIDR;
-
-    uint32_t mClockRate;
-
-    uint32_t mRTPTimeBase;
-    int64_t mNormalPlayTimeBaseUs;
-
-    int64_t mLastNormalPlayTimeUs;
-
-    void updateNormalPlayTime_l(const sp<ABuffer> &buffer);
 
     DISALLOW_EVIL_CONSTRUCTORS(APacketSource);
 };
diff --git a/media/libstagefright/rtsp/ARTSPController.cpp b/media/libstagefright/rtsp/ARTSPController.cpp
deleted file mode 100644
index 2ebae7e..0000000
--- a/media/libstagefright/rtsp/ARTSPController.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ARTSPController.h"
-
-#include "MyHandler.h"
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-ARTSPController::ARTSPController(const sp<ALooper> &looper)
-    : mState(DISCONNECTED),
-      mLooper(looper),
-      mUIDValid(false),
-      mSeekDoneCb(NULL),
-      mSeekDoneCookie(NULL),
-      mLastSeekCompletedTimeUs(-1) {
-    mReflector = new AHandlerReflector<ARTSPController>(this);
-    looper->registerHandler(mReflector);
-}
-
-ARTSPController::~ARTSPController() {
-    CHECK_EQ((int)mState, (int)DISCONNECTED);
-    mLooper->unregisterHandler(mReflector->id());
-}
-
-void ARTSPController::setUID(uid_t uid) {
-    mUIDValid = true;
-    mUID = uid;
-}
-
-status_t ARTSPController::connect(const char *url) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mState != DISCONNECTED) {
-        return ERROR_ALREADY_CONNECTED;
-    }
-
-    sp<AMessage> msg = new AMessage(kWhatConnectDone, mReflector->id());
-
-    mHandler = new MyHandler(url, mLooper, mUIDValid, mUID);
-
-    mState = CONNECTING;
-
-    mHandler->connect(msg);
-
-    while (mState == CONNECTING) {
-        mCondition.wait(mLock);
-    }
-
-    if (mState != CONNECTED) {
-        mHandler.clear();
-    }
-
-    return mConnectionResult;
-}
-
-void ARTSPController::disconnect() {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mState == CONNECTING) {
-        mState = DISCONNECTED;
-        mConnectionResult = ERROR_IO;
-        mCondition.broadcast();
-
-        mHandler.clear();
-        return;
-    } else if (mState != CONNECTED) {
-        return;
-    }
-
-    sp<AMessage> msg = new AMessage(kWhatDisconnectDone, mReflector->id());
-    mHandler->disconnect(msg);
-
-    while (mState == CONNECTED) {
-        mCondition.wait(mLock);
-    }
-
-    mHandler.clear();
-}
-
-void ARTSPController::seekAsync(
-        int64_t timeUs,
-        void (*seekDoneCb)(void *), void *cookie) {
-    Mutex::Autolock autoLock(mLock);
-
-    CHECK(seekDoneCb != NULL);
-    CHECK(mSeekDoneCb == NULL);
-
-    // Ignore seek requests that are too soon after the previous one has
-    // completed, we don't want to swamp the server.
-
-    bool tooEarly =
-        mLastSeekCompletedTimeUs >= 0
-            && ALooper::GetNowUs() < mLastSeekCompletedTimeUs + 500000ll;
-
-    if (mState != CONNECTED || tooEarly) {
-        (*seekDoneCb)(cookie);
-        return;
-    }
-
-    mSeekDoneCb = seekDoneCb;
-    mSeekDoneCookie = cookie;
-
-    sp<AMessage> msg = new AMessage(kWhatSeekDone, mReflector->id());
-    mHandler->seek(timeUs, msg);
-}
-
-size_t ARTSPController::countTracks() {
-    if (mHandler == NULL) {
-        return 0;
-    }
-
-    return mHandler->countTracks();
-}
-
-sp<MediaSource> ARTSPController::getTrack(size_t index) {
-    CHECK(mHandler != NULL);
-
-    return mHandler->getPacketSource(index);
-}
-
-sp<MetaData> ARTSPController::getTrackMetaData(
-        size_t index, uint32_t flags) {
-    CHECK(mHandler != NULL);
-
-    return mHandler->getPacketSource(index)->getFormat();
-}
-
-void ARTSPController::onMessageReceived(const sp<AMessage> &msg) {
-    switch (msg->what()) {
-        case kWhatConnectDone:
-        {
-            Mutex::Autolock autoLock(mLock);
-
-            CHECK(msg->findInt32("result", &mConnectionResult));
-            mState = (mConnectionResult == OK) ? CONNECTED : DISCONNECTED;
-
-            mCondition.signal();
-            break;
-        }
-
-        case kWhatDisconnectDone:
-        {
-            Mutex::Autolock autoLock(mLock);
-            mState = DISCONNECTED;
-            mCondition.signal();
-            break;
-        }
-
-        case kWhatSeekDone:
-        {
-            LOGI("seek done");
-
-            mLastSeekCompletedTimeUs = ALooper::GetNowUs();
-
-            void (*seekDoneCb)(void *) = mSeekDoneCb;
-            mSeekDoneCb = NULL;
-
-            (*seekDoneCb)(mSeekDoneCookie);
-            break;
-        }
-
-        default:
-            TRESPASS();
-            break;
-    }
-}
-
-int64_t ARTSPController::getNormalPlayTimeUs() {
-    CHECK(mHandler != NULL);
-    return mHandler->getNormalPlayTimeUs();
-}
-
-int64_t ARTSPController::getQueueDurationUs(bool *eos) {
-    *eos = true;
-
-    int64_t minQueuedDurationUs = 0;
-    for (size_t i = 0; i < mHandler->countTracks(); ++i) {
-        sp<APacketSource> source = mHandler->getPacketSource(i);
-
-        bool newEOS;
-        int64_t queuedDurationUs = source->getQueueDurationUs(&newEOS);
-
-        if (!newEOS) {
-            *eos = false;
-        }
-
-        if (i == 0 || queuedDurationUs < minQueuedDurationUs) {
-            minQueuedDurationUs = queuedDurationUs;
-        }
-    }
-
-    return minQueuedDurationUs;
-}
-
-}  // namespace android
diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk
index 8530ff3..8230347 100644
--- a/media/libstagefright/rtsp/Android.mk
+++ b/media/libstagefright/rtsp/Android.mk
@@ -15,7 +15,6 @@
         ARTPSource.cpp              \
         ARTPWriter.cpp              \
         ARTSPConnection.cpp         \
-        ARTSPController.cpp         \
         ASessionDescription.cpp     \
 
 LOCAL_C_INCLUDES:= \
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 8128813..af7dd23 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -94,12 +94,24 @@
 }
 
 struct MyHandler : public AHandler {
+    enum {
+        kWhatConnected                  = 'conn',
+        kWhatDisconnected               = 'disc',
+        kWhatSeekDone                   = 'sdon',
+
+        kWhatAccessUnit                 = 'accU',
+        kWhatEOS                        = 'eos!',
+        kWhatSeekDiscontinuity          = 'seeD',
+        kWhatNormalPlayTimeMapping      = 'nptM',
+    };
+
     MyHandler(
-            const char *url, const sp<ALooper> &looper,
+            const char *url,
+            const sp<AMessage> &notify,
             bool uidValid = false, uid_t uid = 0)
-        : mUIDValid(uidValid),
+        : mNotify(notify),
+          mUIDValid(uidValid),
           mUID(uid),
-          mLooper(looper),
           mNetLooper(new ALooper),
           mConn(new ARTSPConnection(mUIDValid, mUID)),
           mRTPConn(new ARTPConnection),
@@ -145,12 +157,9 @@
         mSessionHost = host;
     }
 
-    void connect(const sp<AMessage> &doneMsg) {
-        mDoneMsg = doneMsg;
-
-        mLooper->registerHandler(this);
-        mLooper->registerHandler(mConn);
-        (1 ? mNetLooper : mLooper)->registerHandler(mRTPConn);
+    void connect() {
+        looper()->registerHandler(mConn);
+        (1 ? mNetLooper : looper())->registerHandler(mRTPConn);
 
         sp<AMessage> notify = new AMessage('biny', id());
         mConn->observeBinaryData(notify);
@@ -159,33 +168,16 @@
         mConn->connect(mOriginalSessionURL.c_str(), reply);
     }
 
-    void disconnect(const sp<AMessage> &doneMsg) {
-        mDoneMsg = doneMsg;
-
+    void disconnect() {
         (new AMessage('abor', id()))->post();
     }
 
-    void seek(int64_t timeUs, const sp<AMessage> &doneMsg) {
+    void seek(int64_t timeUs) {
         sp<AMessage> msg = new AMessage('seek', id());
         msg->setInt64("time", timeUs);
-        msg->setMessage("doneMsg", doneMsg);
         msg->post();
     }
 
-    int64_t getNormalPlayTimeUs() {
-        int64_t maxTimeUs = 0;
-        for (size_t i = 0; i < mTracks.size(); ++i) {
-            int64_t timeUs = mTracks.editItemAt(i).mPacketSource
-                ->getNormalPlayTimeUs();
-
-            if (i == 0 || timeUs > maxTimeUs) {
-                maxTimeUs = timeUs;
-            }
-        }
-
-        return maxTimeUs;
-    }
-
     static void addRR(const sp<ABuffer> &buf) {
         uint8_t *ptr = buf->data() + buf->size();
         ptr[0] = 0x80 | 0;
@@ -619,7 +611,9 @@
                 for (size_t i = 0; i < mTracks.size(); ++i) {
                     TrackInfo *info = &mTracks.editItemAt(i);
 
-                    info->mPacketSource->signalEOS(ERROR_END_OF_STREAM);
+                    if (!mFirstAccessUnit) {
+                        postQueueEOS(i, ERROR_END_OF_STREAM);
+                    }
 
                     if (!info->mUsingInterleavedTCP) {
                         mRTPConn->removeStream(info->mRTPSocket, info->mRTCPSocket);
@@ -690,11 +684,10 @@
 
             case 'quit':
             {
-                if (mDoneMsg != NULL) {
-                    mDoneMsg->setInt32("result", UNKNOWN_ERROR);
-                    mDoneMsg->post();
-                    mDoneMsg = NULL;
-                }
+                sp<AMessage> msg = mNotify->dup();
+                msg->setInt32("what", kWhatDisconnected);
+                msg->setInt32("result", UNKNOWN_ERROR);
+                msg->post();
                 break;
             }
 
@@ -795,17 +788,12 @@
 
             case 'seek':
             {
-                sp<AMessage> doneMsg;
-                CHECK(msg->findMessage("doneMsg", &doneMsg));
-
-                if (mSeekPending) {
-                    doneMsg->post();
-                    break;
-                }
-
                 if (!mSeekable) {
                     LOGW("This is a live stream, ignoring seek request.");
-                    doneMsg->post();
+
+                    sp<AMessage> msg = mNotify->dup();
+                    msg->setInt32("what", kWhatSeekDone);
+                    msg->post();
                     break;
                 }
 
@@ -831,7 +819,6 @@
 
                 sp<AMessage> reply = new AMessage('see1', id());
                 reply->setInt64("time", timeUs);
-                reply->setMessage("doneMsg", doneMsg);
                 mConn->sendRequest(request.c_str(), reply);
                 break;
             }
@@ -842,7 +829,8 @@
                 for (size_t i = 0; i < mTracks.size(); ++i) {
                     TrackInfo *info = &mTracks.editItemAt(i);
 
-                    info->mPacketSource->flushQueue();
+                    postQueueSeekDiscontinuity(i);
+
                     info->mRTPAnchor = 0;
                     info->mNTPAnchorUs = -1;
                 }
@@ -866,11 +854,7 @@
 
                 request.append("\r\n");
 
-                sp<AMessage> doneMsg;
-                CHECK(msg->findMessage("doneMsg", &doneMsg));
-
                 sp<AMessage> reply = new AMessage('see2', id());
-                reply->setMessage("doneMsg", doneMsg);
                 mConn->sendRequest(request.c_str(), reply);
                 break;
             }
@@ -915,10 +899,9 @@
 
                 mSeekPending = false;
 
-                sp<AMessage> doneMsg;
-                CHECK(msg->findMessage("doneMsg", &doneMsg));
-
-                doneMsg->post();
+                sp<AMessage> msg = mNotify->dup();
+                msg->setInt32("what", kWhatSeekDone);
+                msg->post();
                 break;
             }
 
@@ -1056,8 +1039,14 @@
 
             LOGV("track #%d: rtpTime=%u <=> npt=%.2f", n, rtpTime, npt1);
 
-            info->mPacketSource->setNormalPlayTimeMapping(
-                    rtpTime, (int64_t)(npt1 * 1E6));
+            info->mNormalPlayTimeRTP = rtpTime;
+            info->mNormalPlayTimeUs = (int64_t)(npt1 * 1E6);
+
+            if (!mFirstAccessUnit) {
+                postNormalPlayTimeMapping(
+                        trackIndex,
+                        info->mNormalPlayTimeRTP, info->mNormalPlayTimeUs);
+            }
 
             ++n;
         }
@@ -1065,11 +1054,15 @@
         mSeekable = true;
     }
 
-    sp<APacketSource> getPacketSource(size_t index) {
+    sp<MetaData> getTrackFormat(size_t index, int32_t *timeScale) {
         CHECK_GE(index, 0u);
         CHECK_LT(index, mTracks.size());
 
-        return mTracks.editItemAt(index).mPacketSource;
+        const TrackInfo &info = mTracks.itemAt(index);
+
+        *timeScale = info.mTimeScale;
+
+        return info.mPacketSource->getFormat();
     }
 
     size_t countTracks() const {
@@ -1089,6 +1082,9 @@
         int64_t mNTPAnchorUs;
         int32_t mTimeScale;
 
+        uint32_t mNormalPlayTimeRTP;
+        int64_t mNormalPlayTimeUs;
+
         sp<APacketSource> mPacketSource;
 
         // Stores packets temporarily while no notion of time
@@ -1096,9 +1092,9 @@
         List<sp<ABuffer> > mPackets;
     };
 
+    sp<AMessage> mNotify;
     bool mUIDValid;
     uid_t mUID;
-    sp<ALooper> mLooper;
     sp<ALooper> mNetLooper;
     sp<ARTSPConnection> mConn;
     sp<ARTPConnection> mRTPConn;
@@ -1127,8 +1123,6 @@
 
     Vector<TrackInfo> mTracks;
 
-    sp<AMessage> mDoneMsg;
-
     void setupTrack(size_t index) {
         sp<APacketSource> source =
             new APacketSource(mSessionDesc, index);
@@ -1158,6 +1152,8 @@
         info->mNewSegment = true;
         info->mRTPAnchor = 0;
         info->mNTPAnchorUs = -1;
+        info->mNormalPlayTimeRTP = 0;
+        info->mNormalPlayTimeUs = 0ll;
 
         unsigned long PT;
         AString formatDesc;
@@ -1283,9 +1279,17 @@
         LOGV("onAccessUnitComplete track %d", trackIndex);
 
         if (mFirstAccessUnit) {
-            mDoneMsg->setInt32("result", OK);
-            mDoneMsg->post();
-            mDoneMsg = NULL;
+            sp<AMessage> msg = mNotify->dup();
+            msg->setInt32("what", kWhatConnected);
+            msg->post();
+
+            for (size_t i = 0; i < mTracks.size(); ++i) {
+                TrackInfo *info = &mTracks.editItemAt(i);
+
+                postNormalPlayTimeMapping(
+                        i,
+                        info->mNormalPlayTimeRTP, info->mNormalPlayTimeUs);
+            }
 
             mFirstAccessUnit = false;
         }
@@ -1303,12 +1307,12 @@
             track->mPackets.erase(track->mPackets.begin());
 
             if (addMediaTimestamp(trackIndex, track, accessUnit)) {
-                track->mPacketSource->queueAccessUnit(accessUnit);
+                postQueueAccessUnit(trackIndex, accessUnit);
             }
         }
 
         if (addMediaTimestamp(trackIndex, track, accessUnit)) {
-            track->mPacketSource->queueAccessUnit(accessUnit);
+            postQueueAccessUnit(trackIndex, accessUnit);
         }
     }
 
@@ -1344,6 +1348,39 @@
         return true;
     }
 
+    void postQueueAccessUnit(
+            size_t trackIndex, const sp<ABuffer> &accessUnit) {
+        sp<AMessage> msg = mNotify->dup();
+        msg->setInt32("what", kWhatAccessUnit);
+        msg->setSize("trackIndex", trackIndex);
+        msg->setObject("accessUnit", accessUnit);
+        msg->post();
+    }
+
+    void postQueueEOS(size_t trackIndex, status_t finalResult) {
+        sp<AMessage> msg = mNotify->dup();
+        msg->setInt32("what", kWhatEOS);
+        msg->setSize("trackIndex", trackIndex);
+        msg->setInt32("finalResult", finalResult);
+        msg->post();
+    }
+
+    void postQueueSeekDiscontinuity(size_t trackIndex) {
+        sp<AMessage> msg = mNotify->dup();
+        msg->setInt32("what", kWhatSeekDiscontinuity);
+        msg->setSize("trackIndex", trackIndex);
+        msg->post();
+    }
+
+    void postNormalPlayTimeMapping(
+            size_t trackIndex, uint32_t rtpTime, int64_t nptUs) {
+        sp<AMessage> msg = mNotify->dup();
+        msg->setInt32("what", kWhatNormalPlayTimeMapping);
+        msg->setSize("trackIndex", trackIndex);
+        msg->setInt32("rtpTime", rtpTime);
+        msg->setInt64("nptUs", nptUs);
+        msg->post();
+    }
 
     DISALLOW_EVIL_CONSTRUCTORS(MyHandler);
 };
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 4c7f84e..0b4f403 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -768,6 +768,9 @@
      * {@link GLSurfaceView#setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory)}
      */
     public interface EGLWindowSurfaceFactory {
+        /**
+         *  @return null if the surface cannot be constructed.
+         */
         EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config,
                 Object nativeWindow);
         void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface);
@@ -777,7 +780,19 @@
 
         public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,
                 EGLConfig config, Object nativeWindow) {
-            return egl.eglCreateWindowSurface(display, config, nativeWindow, null);
+            EGLSurface result = null;
+            try {
+                result = egl.eglCreateWindowSurface(display, config, nativeWindow, null);
+            } catch (IllegalArgumentException e) {
+                // This exception indicates that the surface flinger surface
+                // is not valid. This can happen if the surface flinger surface has
+                // been torn down, but the application has not yet been
+                // notified via SurfaceHolder.Callback.surfaceDestroyed.
+                // In theory the application should be notified first,
+                // but in practice sometimes it is not. See b/4588890
+                Log.e(TAG, "eglCreateWindowSurface", e);
+            }
+            return result;
         }
 
         public void destroySurface(EGL10 egl, EGLDisplay display,
@@ -1041,9 +1056,8 @@
                 int error = mEgl.eglGetError();
                 if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
                     Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
-                    return null;
                 }
-                throwEglException("createWindowSurface", error);
+                return null;
             }
 
             /*
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index b05705e..bcb1aa2 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -238,6 +238,11 @@
      * Notify our observers of an interface removal.
      */
     private void notifyInterfaceRemoved(String iface) {
+        // netd already clears out quota and alerts for removed ifaces; update
+        // our sanity-checking state.
+        mActiveAlertIfaces.remove(iface);
+        mActiveQuotaIfaces.remove(iface);
+
         for (INetworkManagementEventObserver obs : mObservers) {
             try {
                 obs.interfaceRemoved(iface);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index feb2c52..b695903 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -368,18 +368,6 @@
                 mCurrentScalingMode);
 
         if (!isFixedSize()) {
-            // we're being resized and there is a freeze display request,
-            // acquire a freeze lock, so that the screen stays put
-            // until we've redrawn at the new size; this is to avoid
-            // glitches upon orientation changes.
-            if (mFlinger->hasFreezeRequest()) {
-                // if the surface is hidden, don't try to acquire the
-                // freeze lock, since hidden surfaces may never redraw
-                if (!(front.flags & ISurfaceComposer::eLayerHidden)) {
-                    mFreezeLock = mFlinger->getFreezeLock();
-                }
-            }
-
             // this will make sure LayerBase::doTransaction doesn't update
             // the drawing state's size
             Layer::State& editDraw(mDrawingState);
@@ -393,14 +381,6 @@
                 temp.requested_h);
     }
 
-    if (temp.sequence != front.sequence) {
-        if (temp.flags & ISurfaceComposer::eLayerHidden || temp.alpha == 0) {
-            // this surface is now hidden, so it shouldn't hold a freeze lock
-            // (it may never redraw, which is fine if it is hidden)
-            mFreezeLock.clear();
-        }
-    }
-        
     return LayerBase::doTransaction(flags);
 }
 
@@ -474,7 +454,7 @@
         glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
         glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
-        // update the layer size and release freeze-lock
+        // update the layer size if needed
         const Layer::State& front(drawingState());
 
         // FIXME: mPostedDirtyRegion = dirty & bounds
@@ -511,9 +491,6 @@
 
                 // recompute visible region
                 recomputeVisibleRegions = true;
-
-                // we now have the correct size, unfreeze the screen
-                mFreezeLock.clear();
             }
 
             LOGD_IF(DEBUG_RESIZE,
@@ -546,11 +523,6 @@
         dirtyRegion.andSelf(visibleRegionScreen);
         outDirtyRegion.orSelf(dirtyRegion);
     }
-    if (visibleRegionScreen.isEmpty()) {
-        // an invisible layer should not hold a freeze-lock
-        // (because it may never be updated and therefore never release it)
-        mFreezeLock.clear();
-    }
 }
 
 void Layer::dump(String8& result, char* buffer, size_t SIZE) const
@@ -568,9 +540,9 @@
     snprintf(buffer, SIZE,
             "      "
             "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X],"
-            " freezeLock=%p, transform-hint=0x%02x, queued-frames=%d\n",
+            " transform-hint=0x%02x, queued-frames=%d\n",
             mFormat, w0, h0, s0,f0,
-            getFreezeLock().get(), getTransformHint(), mQueuedFrames);
+            getTransformHint(), mQueuedFrames);
 
     result.append(buffer);
 
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 82e3521..2b9471b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -39,7 +39,6 @@
 
 // ---------------------------------------------------------------------------
 
-class FreezeLock;
 class Client;
 class GLExtensions;
 
@@ -80,7 +79,6 @@
     virtual wp<IBinder> getSurfaceTextureBinder() const;
 
     // only for debugging
-    inline const sp<FreezeLock>&  getFreezeLock() const { return mFreezeLock; }
     inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }
 
 protected:
@@ -124,9 +122,6 @@
     bool mProtectedByApp; // application requires protected path to external sink
     Region mPostedDirtyRegion;
 
-    // page-flip thread and transaction thread (currently main thread)
-    sp<FreezeLock>  mFreezeLock;
-
     // binder thread, transaction thread
     mutable Mutex mLock;
 };
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7c0cd9b..7a8952a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -79,15 +79,12 @@
 SurfaceFlinger::SurfaceFlinger()
     :   BnSurfaceComposer(), Thread(false),
         mTransactionFlags(0),
-        mResizeTransationPending(false),
+        mTransationPending(false),
         mLayersRemoved(false),
         mBootTime(systemTime()),
         mVisibleRegionsDirty(false),
         mHwWorkListDirty(false),
-        mFreezeDisplay(false),
         mElectronBeamAnimationMode(0),
-        mFreezeCount(0),
-        mFreezeDisplayTime(0),
         mDebugRegion(0),
         mDebugBackground(0),
         mDebugDDMS(0),
@@ -190,11 +187,6 @@
 {
     // the window manager died on us. prepare its eulogy.
 
-    // unfreeze the screen in case it was... frozen
-    mFreezeDisplayTime = 0;
-    mFreezeCount = 0;
-    mFreezeDisplay = false;
-
     // reset screen orientation
     setOrientation(0, eOrientationDefault, 0);
 
@@ -322,33 +314,7 @@
 {
     while (true) {
         nsecs_t timeout = -1;
-        const nsecs_t freezeDisplayTimeout = ms2ns(5000);
-        if (UNLIKELY(isFrozen())) {
-            // wait 5 seconds
-            const nsecs_t now = systemTime();
-            if (mFreezeDisplayTime == 0) {
-                mFreezeDisplayTime = now;
-            }
-            nsecs_t waitTime = freezeDisplayTimeout - (now - mFreezeDisplayTime);
-            timeout = waitTime>0 ? waitTime : 0;
-        }
-
         sp<MessageBase> msg = mEventQueue.waitMessage(timeout);
-
-        // see if we timed out
-        if (isFrozen()) {
-            const nsecs_t now = systemTime();
-            nsecs_t frozenTime = (now - mFreezeDisplayTime);
-            if (frozenTime >= freezeDisplayTimeout) {
-                // we timed out and are still frozen
-                LOGW("timeout expired mFreezeDisplay=%d, mFreezeCount=%d",
-                        mFreezeDisplay, mFreezeCount);
-                mFreezeDisplayTime = 0;
-                mFreezeCount = 0;
-                mFreezeDisplay = false;
-            }
-        }
-
         if (msg != 0) {
             switch (msg->what) {
                 case MessageQueue::INVALIDATE:
@@ -580,13 +546,6 @@
             mDirtyRegion.set(hw.bounds());
         }
 
-        if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) {
-            // freezing or unfreezing the display -> trigger animation if needed
-            mFreezeDisplay = mCurrentState.freezeDisplay;
-            if (mFreezeDisplay)
-                 mFreezeDisplayTime = 0;
-        }
-
         if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
             // layers have been added
             mVisibleRegionsDirty = true;
@@ -612,11 +571,6 @@
     commitTransaction();
 }
 
-sp<FreezeLock> SurfaceFlinger::getFreezeLock() const
-{
-    return new FreezeLock(const_cast<SurfaceFlinger *>(this));
-}
-
 void SurfaceFlinger::computeVisibleRegions(
     const LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion)
 {
@@ -746,7 +700,7 @@
 void SurfaceFlinger::commitTransaction()
 {
     mDrawingState = mCurrentState;
-    mResizeTransationPending = false;
+    mTransationPending = false;
     mTransactionCV.broadcast();
 }
 
@@ -1233,15 +1187,14 @@
 
 
 void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& state,
-        int orientation) {
+        int orientation, uint32_t flags) {
     Mutex::Autolock _l(mStateLock);
 
-    uint32_t flags = 0;
+    uint32_t transactionFlags = 0;
     if (mCurrentState.orientation != orientation) {
         if (uint32_t(orientation)<=eOrientation270 || orientation==42) {
             mCurrentState.orientation = orientation;
-            flags |= eTransactionNeeded;
-            mResizeTransationPending = true;
+            transactionFlags |= eTransactionNeeded;
         } else if (orientation != eOrientationUnchanged) {
             LOGW("setTransactionState: ignoring unrecognized orientation: %d",
                     orientation);
@@ -1252,56 +1205,29 @@
     for (size_t i=0 ; i<count ; i++) {
         const ComposerState& s(state[i]);
         sp<Client> client( static_cast<Client *>(s.client.get()) );
-        flags |= setClientStateLocked(client, s.state);
+        transactionFlags |= setClientStateLocked(client, s.state);
     }
-    if (flags) {
-        setTransactionFlags(flags);
+    if (transactionFlags) {
+        setTransactionFlags(transactionFlags);
     }
 
-    signalEvent();
-
-    // if there is a transaction with a resize, wait for it to
-    // take effect before returning.
-    while (mResizeTransationPending) {
+    // if this is a synchronous transaction, wait for it to take effect before
+    // returning.
+    if (flags & eSynchronous) {
+        mTransationPending = true;
+    }
+    while (mTransationPending) {
         status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
         if (CC_UNLIKELY(err != NO_ERROR)) {
             // just in case something goes wrong in SF, return to the
             // called after a few seconds.
             LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!");
-            mResizeTransationPending = false;
+            mTransationPending = false;
             break;
         }
     }
 }
 
-status_t SurfaceFlinger::freezeDisplay(DisplayID dpy, uint32_t flags)
-{
-    if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
-        return BAD_VALUE;
-
-    Mutex::Autolock _l(mStateLock);
-    mCurrentState.freezeDisplay = 1;
-    setTransactionFlags(eTransactionNeeded);
-
-    // flags is intended to communicate some sort of animation behavior
-    // (for instance fading)
-    return NO_ERROR;
-}
-
-status_t SurfaceFlinger::unfreezeDisplay(DisplayID dpy, uint32_t flags)
-{
-    if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
-        return BAD_VALUE;
-
-    Mutex::Autolock _l(mStateLock);
-    mCurrentState.freezeDisplay = 0;
-    setTransactionFlags(eTransactionNeeded);
-
-    // flags is intended to communicate some sort of animation behavior
-    // (for instance fading)
-    return NO_ERROR;
-}
-
 int SurfaceFlinger::setOrientation(DisplayID dpy,
         int orientation, uint32_t flags)
 {
@@ -1487,7 +1413,6 @@
         if (what & eSizeChanged) {
             if (layer->setSize(s.w, s.h)) {
                 flags |= eTraversalNeeded;
-                mResizeTransationPending = true;
             }
         }
         if (what & eAlphaChanged) {
@@ -1607,8 +1532,7 @@
         mWormholeRegion.dump(result, "WormholeRegion");
         const DisplayHardware& hw(graphicPlane(0).displayHardware());
         snprintf(buffer, SIZE,
-                "  display frozen: %s, freezeCount=%d, orientation=%d, canDraw=%d\n",
-                mFreezeDisplay?"yes":"no", mFreezeCount,
+                "  orientation=%d, canDraw=%d\n",
                 mCurrentState.orientation, hw.canDraw());
         result.append(buffer);
         snprintf(buffer, SIZE,
@@ -1661,8 +1585,6 @@
         case CREATE_CONNECTION:
         case SET_TRANSACTION_STATE:
         case SET_ORIENTATION:
-        case FREEZE_DISPLAY:
-        case UNFREEZE_DISPLAY:
         case BOOT_FINISHED:
         case TURN_ELECTRON_BEAM_OFF:
         case TURN_ELECTRON_BEAM_ON:
@@ -1734,10 +1656,6 @@
                 GraphicLog::getInstance().setEnabled(enabled);
                 return NO_ERROR;
             }
-            case 1007: // set mFreezeCount
-                mFreezeCount = data.readInt32();
-                mFreezeDisplayTime = 0;
-                return NO_ERROR;
             case 1008:  // toggle use of hw composer
                 n = data.readInt32();
                 mDebugDisableHWC = n ? 1 : 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0e642c1..eabcc9d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -46,7 +46,6 @@
 
 class Client;
 class DisplayHardware;
-class FreezeLock;
 class Layer;
 class LayerDim;
 struct surface_flinger_cblk_t;
@@ -168,9 +167,7 @@
     virtual sp<IMemoryHeap>             getCblk() const;
     virtual void                        bootFinished();
     virtual void                        setTransactionState(const Vector<ComposerState>& state,
-                                                            int orientation);
-    virtual status_t                    freezeDisplay(DisplayID dpy, uint32_t flags);
-    virtual status_t                    unfreezeDisplay(DisplayID dpy, uint32_t flags);
+                                                            int orientation, uint32_t flags);
     virtual int                         setOrientation(DisplayID dpy, int orientation, uint32_t flags);
     virtual bool                        authenticateSurfaceTexture(const sp<ISurfaceTexture>& surface) const;
 
@@ -244,12 +241,10 @@
     struct State {
         State() {
             orientation = ISurfaceComposer::eOrientationDefault;
-            freezeDisplay = 0;
         }
         LayerVector     layersSortedByZ;
         uint8_t         orientation;
         uint8_t         orientationFlags;
-        uint8_t         freezeDisplay;
     };
 
     virtual bool        threadLoop();
@@ -308,20 +303,6 @@
             status_t renderScreenToTextureLocked(DisplayID dpy,
                     GLuint* textureName, GLfloat* uOut, GLfloat* vOut);
 
-            friend class FreezeLock;
-            sp<FreezeLock> getFreezeLock() const;
-            inline void incFreezeCount() {
-                if (mFreezeCount == 0)
-                    mFreezeDisplayTime = 0;
-                mFreezeCount++;
-            }
-            inline void decFreezeCount() { if (mFreezeCount > 0) mFreezeCount--; }
-            inline bool hasFreezeRequest() const { return mFreezeDisplay; }
-            inline bool isFrozen() const { 
-                return (mFreezeDisplay || mFreezeCount>0) && mBootFinished;
-            }
-
-            
             void        debugFlashRegions();
             void        debugShowFPS() const;
             void        drawWormhole() const;
@@ -341,7 +322,7 @@
     volatile    int32_t                 mTransactionFlags;
                 Condition               mTransactionCV;
                 SortedVector< sp<LayerBase> > mLayerPurgatory;
-                bool                    mResizeTransationPending;
+                bool                    mTransationPending;
 
                 // protected by mStateLock (but we could use another lock)
                 GraphicPlane                mGraphicPlanes[1];
@@ -364,10 +345,7 @@
                 Region                      mWormholeRegion;
                 bool                        mVisibleRegionsDirty;
                 bool                        mHwWorkListDirty;
-                bool                        mFreezeDisplay;
                 int32_t                     mElectronBeamAnimationMode;
-                int32_t                     mFreezeCount;
-                nsecs_t                     mFreezeDisplayTime;
                 Vector< sp<LayerBase> >     mVisibleLayersSortedByZ;
 
 
@@ -403,20 +381,6 @@
 };
 
 // ---------------------------------------------------------------------------
-
-class FreezeLock : public LightRefBase<FreezeLock> {
-    SurfaceFlinger* mFlinger;
-public:
-    FreezeLock(SurfaceFlinger* flinger)
-        : mFlinger(flinger) {
-        mFlinger->incFreezeCount();
-    }
-    ~FreezeLock() {
-        mFlinger->decFreezeCount();
-    }
-};
-
-// ---------------------------------------------------------------------------
 }; // namespace android
 
 #endif // ANDROID_SURFACE_FLINGER_H
diff --git a/services/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk
index 5053e7d..b655648 100644
--- a/services/surfaceflinger/tests/Android.mk
+++ b/services/surfaceflinger/tests/Android.mk
@@ -1 +1,40 @@
-include $(call all-subdir-makefiles)
+# Build the unit tests,
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := SurfaceFlinger_test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+    Transaction_test.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+	libEGL \
+	libGLESv2 \
+	libandroid \
+	libbinder \
+	libcutils \
+	libgui \
+	libstlport \
+	libui \
+	libutils \
+
+LOCAL_C_INCLUDES := \
+    bionic \
+    bionic/libstdc++/include \
+    external/gtest/include \
+    external/stlport/stlport \
+
+# Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
+# to integrate with auto-test framework.
+include $(BUILD_NATIVE_TEST)
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
new file mode 100644
index 0000000..afafd8a
--- /dev/null
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <binder/IMemory.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/Surface.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+#include <utils/String8.h>
+
+namespace android {
+
+// Fill an RGBA_8888 formatted surface with a single color.
+static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc,
+        uint8_t r, uint8_t g, uint8_t b) {
+    Surface::SurfaceInfo info;
+    sp<Surface> s = sc->getSurface();
+    ASSERT_TRUE(s != NULL);
+    ASSERT_EQ(NO_ERROR, s->lock(&info));
+    uint8_t* img = reinterpret_cast<uint8_t*>(info.bits);
+    for (uint32_t y = 0; y < info.h; y++) {
+        for (uint32_t x = 0; x < info.w; x++) {
+            uint8_t* pixel = img + (4 * (y*info.s + x));
+            pixel[0] = r;
+            pixel[1] = g;
+            pixel[2] = b;
+            pixel[3] = 255;
+        }
+    }
+    ASSERT_EQ(NO_ERROR, s->unlockAndPost());
+}
+
+// A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
+// individual pixel values for testing purposes.
+class ScreenCapture : public RefBase {
+public:
+    static void captureScreen(sp<ScreenCapture>* sc) {
+        sp<IMemoryHeap> heap;
+        uint32_t w=0, h=0;
+        PixelFormat fmt=0;
+        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+        ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 0, 0,
+                0, INT_MAX));
+        ASSERT_TRUE(heap != NULL);
+        ASSERT_EQ(PIXEL_FORMAT_RGBA_8888, fmt);
+        *sc = new ScreenCapture(w, h, heap);
+    }
+
+    void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
+        const uint8_t* img = reinterpret_cast<const uint8_t*>(mHeap->base());
+        const uint8_t* pixel = img + (4 * (y*mWidth + x));
+        if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
+            String8 err(String8::format("pixel @ (%3d, %3d): "
+                    "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
+                    x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
+            EXPECT_EQ(String8(), err);
+        }
+    }
+
+private:
+    ScreenCapture(uint32_t w, uint32_t h, const sp<IMemoryHeap>& heap) :
+        mWidth(w),
+        mHeight(h),
+        mHeap(heap)
+    {}
+
+    const uint32_t mWidth;
+    const uint32_t mHeight;
+    sp<IMemoryHeap> mHeap;
+};
+
+class LayerUpdateTest : public ::testing::Test {
+protected:
+    virtual void SetUp() {
+        mComposerClient = new SurfaceComposerClient;
+        ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+        ssize_t displayWidth = mComposerClient->getDisplayWidth(0);
+        ssize_t displayHeight = mComposerClient->getDisplayHeight(0);
+
+        // Background surface
+        mBGSurfaceControl = mComposerClient->createSurface(
+                String8("BG Test Surface"), 0, displayWidth, displayHeight,
+                PIXEL_FORMAT_RGBA_8888, 0);
+        ASSERT_TRUE(mBGSurfaceControl != NULL);
+        ASSERT_TRUE(mBGSurfaceControl->isValid());
+        fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195);
+
+        // Foreground surface
+        mFGSurfaceControl = mComposerClient->createSurface(
+                String8("FG Test Surface"), 0, 64, 64, PIXEL_FORMAT_RGBA_8888, 0);
+        ASSERT_TRUE(mFGSurfaceControl != NULL);
+        ASSERT_TRUE(mFGSurfaceControl->isValid());
+
+        fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+
+        // Synchronization surface
+        mSyncSurfaceControl = mComposerClient->createSurface(
+                String8("Sync Test Surface"), 0, 1, 1, PIXEL_FORMAT_RGBA_8888, 0);
+        ASSERT_TRUE(mSyncSurfaceControl != NULL);
+        ASSERT_TRUE(mSyncSurfaceControl->isValid());
+
+        fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+
+        SurfaceComposerClient::openGlobalTransaction();
+
+        ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT_MAX-2));
+        ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show());
+
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX-1));
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(64, 64));
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show());
+
+        ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->setLayer(INT_MAX-1));
+        ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->setPosition(displayWidth-2,
+                displayHeight-2));
+        ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->show());
+
+        SurfaceComposerClient::closeGlobalTransaction(true);
+    }
+
+    virtual void TearDown() {
+        mComposerClient->dispose();
+        mBGSurfaceControl = 0;
+        mFGSurfaceControl = 0;
+        mSyncSurfaceControl = 0;
+        mComposerClient = 0;
+    }
+
+    void waitForPostedBuffers() {
+        // Since the sync surface is in synchronous mode (i.e. double buffered)
+        // posting three buffers to it should ensure that at least two
+        // SurfaceFlinger::handlePageFlip calls have been made, which should
+        // guaranteed that a buffer posted to another Surface has been retired.
+        fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+        fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+        fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+    }
+
+    sp<SurfaceComposerClient> mComposerClient;
+    sp<SurfaceControl> mBGSurfaceControl;
+    sp<SurfaceControl> mFGSurfaceControl;
+
+    // This surface is used to ensure that the buffers posted to
+    // mFGSurfaceControl have been picked up by SurfaceFlinger.
+    sp<SurfaceControl> mSyncSurfaceControl;
+};
+
+TEST_F(LayerUpdateTest, LayerMoveWorks) {
+    sp<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before move");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(  0,  12,  63,  63, 195);
+        sc->checkPixel( 75,  75, 195,  63,  63);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+
+    SurfaceComposerClient::openGlobalTransaction();
+    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+    {
+        // This should reflect the new position, but not the new color.
+        SCOPED_TRACE("after move, before redraw");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75,  63,  63, 195);
+        sc->checkPixel(145, 145, 195,  63,  63);
+    }
+
+    fillSurfaceRGBA8(mFGSurfaceControl, 63, 195, 63);
+    waitForPostedBuffers();
+    {
+        // This should reflect the new position and the new color.
+        SCOPED_TRACE("after redraw");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75,  63,  63, 195);
+        sc->checkPixel(145, 145,  63, 195,  63);
+    }
+}
+
+TEST_F(LayerUpdateTest, LayerResizeWorks) {
+    sp<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before resize");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(  0,  12,  63,  63, 195);
+        sc->checkPixel( 75,  75, 195,  63,  63);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+
+    LOGD("resizing");
+    SurfaceComposerClient::openGlobalTransaction();
+    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setSize(128, 128));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+    LOGD("resized");
+    {
+        // This should not reflect the new size or color because SurfaceFlinger
+        // has not yet received a buffer of the correct size.
+        SCOPED_TRACE("after resize, before redraw");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(  0,  12,  63,  63, 195);
+        sc->checkPixel( 75,  75, 195,  63,  63);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+
+    LOGD("drawing");
+    fillSurfaceRGBA8(mFGSurfaceControl, 63, 195, 63);
+    waitForPostedBuffers();
+    LOGD("drawn");
+    {
+        // This should reflect the new size and the new color.
+        SCOPED_TRACE("after redraw");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75,  63, 195,  63);
+        sc->checkPixel(145, 145,  63, 195,  63);
+    }
+}
+
+}
diff --git a/telephony/java/com/android/internal/telephony/IccProvider.java b/telephony/java/com/android/internal/telephony/IccProvider.java
index 3471ec2..a66e19d 100644
--- a/telephony/java/com/android/internal/telephony/IccProvider.java
+++ b/telephony/java/com/android/internal/telephony/IccProvider.java
@@ -19,166 +19,20 @@
 import android.content.ContentProvider;
 import android.content.UriMatcher;
 import android.content.ContentValues;
-import android.database.AbstractCursor;
 import android.database.Cursor;
-import android.database.CursorWindow;
+import android.database.MatrixCursor;
 import android.net.Uri;
-import android.os.SystemProperties;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.text.TextUtils;
 import android.util.Log;
 
-import java.util.ArrayList;
 import java.util.List;
 
 import com.android.internal.telephony.IccConstants;
 import com.android.internal.telephony.AdnRecord;
 import com.android.internal.telephony.IIccPhoneBook;
 
-/**
- * XXX old code -- should be replaced with MatrixCursor.
- * @deprecated This is has been replaced by MatrixCursor.
-*/
-class ArrayListCursor extends AbstractCursor {
-    private String[] mColumnNames;
-    private ArrayList<Object>[] mRows;
-
-    @SuppressWarnings({"unchecked"})
-    public ArrayListCursor(String[] columnNames, ArrayList<ArrayList> rows) {
-        int colCount = columnNames.length;
-        boolean foundID = false;
-        // Add an _id column if not in columnNames
-        for (int i = 0; i < colCount; ++i) {
-            if (columnNames[i].compareToIgnoreCase("_id") == 0) {
-                mColumnNames = columnNames;
-                foundID = true;
-                break;
-            }
-        }
-
-        if (!foundID) {
-            mColumnNames = new String[colCount + 1];
-            System.arraycopy(columnNames, 0, mColumnNames, 0, columnNames.length);
-            mColumnNames[colCount] = "_id";
-        }
-
-        int rowCount = rows.size();
-        mRows = new ArrayList[rowCount];
-
-        for (int i = 0; i < rowCount; ++i) {
-            mRows[i] = rows.get(i);
-            if (!foundID) {
-                mRows[i].add(i);
-            }
-        }
-    }
-
-    @Override
-    public void fillWindow(int position, CursorWindow window) {
-        if (position < 0 || position > getCount()) {
-            return;
-        }
-
-        window.acquireReference();
-        try {
-            int oldpos = mPos;
-            mPos = position - 1;
-            window.clear();
-            window.setStartPosition(position);
-            int columnNum = getColumnCount();
-            window.setNumColumns(columnNum);
-            while (moveToNext() && window.allocRow()) {
-                for (int i = 0; i < columnNum; i++) {
-                    final Object data = mRows[mPos].get(i);
-                    if (data != null) {
-                        if (data instanceof byte[]) {
-                            byte[] field = (byte[]) data;
-                            if (!window.putBlob(field, mPos, i)) {
-                                window.freeLastRow();
-                                break;
-                            }
-                        } else {
-                            String field = data.toString();
-                            if (!window.putString(field, mPos, i)) {
-                                window.freeLastRow();
-                                break;
-                            }
-                        }
-                    } else {
-                        if (!window.putNull(mPos, i)) {
-                            window.freeLastRow();
-                            break;
-                        }
-                    }
-                }
-            }
-
-            mPos = oldpos;
-        } catch (IllegalStateException e){
-            // simply ignore it
-        } finally {
-            window.releaseReference();
-        }
-    }
-
-    @Override
-    public int getCount() {
-        return mRows.length;
-    }
-
-    @Override
-    public String[] getColumnNames() {
-        return mColumnNames;
-    }
-
-    @Override
-    public byte[] getBlob(int columnIndex) {
-        return (byte[]) mRows[mPos].get(columnIndex);
-    }
-
-    @Override
-    public String getString(int columnIndex) {
-        Object cell = mRows[mPos].get(columnIndex);
-        return (cell == null) ? null : cell.toString();
-    }
-
-    @Override
-    public short getShort(int columnIndex) {
-        Number num = (Number) mRows[mPos].get(columnIndex);
-        return num.shortValue();
-    }
-
-    @Override
-    public int getInt(int columnIndex) {
-        Number num = (Number) mRows[mPos].get(columnIndex);
-        return num.intValue();
-    }
-
-    @Override
-    public long getLong(int columnIndex) {
-        Number num = (Number) mRows[mPos].get(columnIndex);
-        return num.longValue();
-    }
-
-    @Override
-    public float getFloat(int columnIndex) {
-        Number num = (Number) mRows[mPos].get(columnIndex);
-        return num.floatValue();
-    }
-
-    @Override
-    public double getDouble(int columnIndex) {
-        Number num = (Number) mRows[mPos].get(columnIndex);
-        return num.doubleValue();
-    }
-
-    @Override
-    public boolean isNull(int columnIndex) {
-        return mRows[mPos].get(columnIndex) == null;
-    }
-}
-
 
 /**
  * {@hide}
@@ -191,7 +45,8 @@
     private static final String[] ADDRESS_BOOK_COLUMN_NAMES = new String[] {
         "name",
         "number",
-        "emails"
+        "emails",
+        "_id"
     };
 
     private static final int ADN = 1;
@@ -213,70 +68,27 @@
     }
 
 
-    private boolean mSimulator;
-
     @Override
     public boolean onCreate() {
-        String device = SystemProperties.get("ro.product.device");
-        if (!TextUtils.isEmpty(device)) {
-            mSimulator = false;
-        } else {
-            // simulator
-            mSimulator = true;
-        }
-
         return true;
     }
 
     @Override
     public Cursor query(Uri url, String[] projection, String selection,
             String[] selectionArgs, String sort) {
-        ArrayList<ArrayList> results;
+        switch (URL_MATCHER.match(url)) {
+            case ADN:
+                return loadFromEf(IccConstants.EF_ADN);
 
-        if (!mSimulator) {
-            switch (URL_MATCHER.match(url)) {
-                case ADN:
-                    results = loadFromEf(IccConstants.EF_ADN);
-                    break;
+            case FDN:
+                return loadFromEf(IccConstants.EF_FDN);
 
-                case FDN:
-                    results = loadFromEf(IccConstants.EF_FDN);
-                    break;
+            case SDN:
+                return loadFromEf(IccConstants.EF_SDN);
 
-                case SDN:
-                    results = loadFromEf(IccConstants.EF_SDN);
-                    break;
-
-                default:
-                    throw new IllegalArgumentException("Unknown URL " + url);
-            }
-        } else {
-            // Fake up some data for the simulator
-            results = new ArrayList<ArrayList>(4);
-            ArrayList<String> contact;
-
-            contact = new ArrayList<String>();
-            contact.add("Ron Stevens/H");
-            contact.add("512-555-5038");
-            results.add(contact);
-
-            contact = new ArrayList<String>();
-            contact.add("Ron Stevens/M");
-            contact.add("512-555-8305");
-            results.add(contact);
-
-            contact = new ArrayList<String>();
-            contact.add("Melissa Owens");
-            contact.add("512-555-8305");
-            results.add(contact);
-
-            contact = new ArrayList<String>();
-            contact.add("Directory Assistence");
-            contact.add("411");
-            results.add(contact);
+            default:
+                throw new IllegalArgumentException("Unknown URL " + url);
         }
-
-        return new ArrayListCursor(ADDRESS_BOOK_COLUMN_NAMES, results);
     }
 
     @Override
@@ -473,12 +285,10 @@
         return 1;
     }
 
-    private ArrayList<ArrayList> loadFromEf(int efType) {
-        ArrayList<ArrayList> results = new ArrayList<ArrayList>();
-        List<AdnRecord> adnRecords = null;
-
+    private MatrixCursor loadFromEf(int efType) {
         if (DBG) log("loadFromEf: efType=" + efType);
 
+        List<AdnRecord> adnRecords = null;
         try {
             IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
                     ServiceManager.getService("simphonebook"));
@@ -490,21 +300,21 @@
         } catch (SecurityException ex) {
             if (DBG) log(ex.toString());
         }
+
         if (adnRecords != null) {
             // Load the results
-
-            int N = adnRecords.size();
+            final int N = adnRecords.size();
+            final MatrixCursor cursor = new MatrixCursor(ADDRESS_BOOK_COLUMN_NAMES, N);
             if (DBG) log("adnRecords.size=" + N);
             for (int i = 0; i < N ; i++) {
-                loadRecord(adnRecords.get(i), results);
+                loadRecord(adnRecords.get(i), cursor, i);
             }
+            return cursor;
         } else {
             // No results to load
             Log.w(TAG, "Cannot load ADN records");
-            results.clear();
+            return new MatrixCursor(ADDRESS_BOOK_COLUMN_NAMES);
         }
-        if (DBG) log("loadFromEf: return results");
-        return results;
     }
 
     private boolean
@@ -584,35 +394,33 @@
     }
 
     /**
-     * Loads an AdnRecord into an ArrayList. Must be called with mLock held.
+     * Loads an AdnRecord into a MatrixCursor. Must be called with mLock held.
      *
      * @param record the ADN record to load from
-     * @param results the array list to put the results in
+     * @param cursor the cursor to receive the results
      */
-    private void loadRecord(AdnRecord record,
-            ArrayList<ArrayList> results) {
+    private void loadRecord(AdnRecord record, MatrixCursor cursor, int id) {
         if (!record.isEmpty()) {
-            ArrayList<String> contact = new ArrayList<String>();
+            Object[] contact = new Object[4];
             String alphaTag = record.getAlphaTag();
             String number = record.getNumber();
-            String[] emails = record.getEmails();
 
             if (DBG) log("loadRecord: " + alphaTag + ", " + number + ",");
-            contact.add(alphaTag);
-            contact.add(number);
-            StringBuilder emailString = new StringBuilder();
+            contact[0] = alphaTag;
+            contact[1] = number;
 
+            String[] emails = record.getEmails();
             if (emails != null) {
+                StringBuilder emailString = new StringBuilder();
                 for (String email: emails) {
                     if (DBG) log("Adding email:" + email);
                     emailString.append(email);
                     emailString.append(",");
                 }
-                contact.add(emailString.toString());
-            } else {
-                contact.add(null);
+                contact[2] = emailString.toString();
             }
-            results.add(contact);
+            contact[3] = id;
+            cursor.addRow(contact);
         }
     }
 
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
index 3232eedc..414ae0d 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
@@ -22,9 +22,11 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.graphics.Matrix;
 import android.graphics.SurfaceTexture;
 import android.opengl.GLUtils;
 import android.os.Bundle;
+import android.os.Environment;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.TextureView;
@@ -39,6 +41,7 @@
 import javax.microedition.khronos.egl.EGLSurface;
 import javax.microedition.khronos.opengles.GL;
 import java.io.BufferedOutputStream;
+import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -65,7 +68,8 @@
                 Bitmap b = mTextureView.getBitmap(800, 800);
                 BufferedOutputStream out = null;
                 try {
-                    out = new BufferedOutputStream(new FileOutputStream("/sdcard/out.png"));
+                    File dump = new File(Environment.getExternalStorageDirectory(), "out.png");
+                    out = new BufferedOutputStream(new FileOutputStream(dump));
                     b.compress(Bitmap.CompressFormat.PNG, 100, out);
                 } catch (FileNotFoundException e) {
                     e.printStackTrace();
@@ -168,10 +172,10 @@
         private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
         private final float[] mTriangleVerticesData = {
                 // X, Y, Z, U, V
-                -1.0f, -1.0f, 0, 0.f, 0.f,
-                1.0f, -1.0f, 0, 1.f, 0.f,
-                -1.0f,  1.0f, 0, 0.f, 1.f,
-                1.0f,   1.0f, 0, 1.f, 1.f,
+                -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
+                 1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
+                -1.0f,  1.0f, 0.0f, 0.0f, 1.0f,
+                 1.0f,  1.0f, 0.0f, 1.0f, 1.0f,
         };
 
         @Override
@@ -212,8 +216,6 @@
             while (!mFinished) {
                 checkCurrent();
 
-                Log.d(LOG_TAG, "Rendering frame");
-
                 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
                 checkGlError();
 
@@ -237,7 +239,7 @@
                 checkEglError();
 
                 try {
-                    Thread.sleep(20);
+                    Thread.sleep(2000);
                 } catch (InterruptedException e) {
                     // Ignore
                 }
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
index fcb57d9..0f4c668 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
@@ -17,16 +17,23 @@
 package com.android.test.hwui;
 
 import android.app.Activity;
+import android.graphics.Bitmap;
 import android.graphics.Matrix;
 import android.graphics.SurfaceTexture;
 import android.hardware.Camera;
 import android.os.Bundle;
+import android.os.Environment;
 import android.view.Gravity;
+import android.view.Surface;
 import android.view.TextureView;
 import android.view.View;
 import android.widget.Button;
 import android.widget.FrameLayout;
 
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
 
 @SuppressWarnings({"UnusedDeclaration"})
@@ -44,6 +51,26 @@
 
         mTextureView = new TextureView(this);
         mTextureView.setSurfaceTextureListener(this);
+        mTextureView.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Bitmap b = mTextureView.getBitmap(800, 800);
+                BufferedOutputStream out = null;
+                try {
+                    File dump = new File(Environment.getExternalStorageDirectory(), "out.png");
+                    out = new BufferedOutputStream(new FileOutputStream(dump));
+                    b.compress(Bitmap.CompressFormat.PNG, 100, out);
+                } catch (FileNotFoundException e) {
+                    e.printStackTrace();
+                } finally {
+                    if (out != null) try {
+                        out.close();
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        });
 
         Button button = new Button(this);
         button.setText("Remove/Add");
@@ -73,6 +100,8 @@
     @Override
     public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
         mCamera = Camera.open();
+        mCamera.setDisplayOrientation(getCameraOrientation());
+
         Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
         mTextureView.setLayoutParams(new FrameLayout.LayoutParams(
                 previewSize.width, previewSize.height, Gravity.CENTER));
@@ -86,6 +115,34 @@
         mCamera.startPreview();
     }
 
+    private int getCameraOrientation() {
+        Camera.CameraInfo info = new Camera.CameraInfo();
+        for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
+            Camera.getCameraInfo(i, info);
+            if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) break;
+        }
+        
+        int rotation = getWindowManager().getDefaultDisplay().getRotation();
+        int degrees = 0;
+
+        switch (rotation) {
+            case Surface.ROTATION_0:
+                degrees = 0;
+                break;
+            case Surface.ROTATION_90:
+                degrees = 90;
+                break;
+            case Surface.ROTATION_180:
+                degrees = 180;
+                break;
+            case Surface.ROTATION_270:
+                degrees = 270;
+                break;
+        }
+
+        return (info.orientation - degrees + 360) % 360;
+    }
+
     @Override
     public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
         // Ignored, the Camera does all the work for us
diff --git a/tests/RenderScriptTests/ComputePerf/Android.mk b/tests/RenderScriptTests/ComputePerf/Android.mk
new file mode 100644
index 0000000..1d67d29
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/Android.mk
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+                   $(call all-renderscript-files-under, src)
+
+LOCAL_PACKAGE_NAME := RsComputePerf
+
+include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/ComputePerf/AndroidManifest.xml b/tests/RenderScriptTests/ComputePerf/AndroidManifest.xml
new file mode 100644
index 0000000..a9193b5
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.rs.computeperf">
+
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />    
+    <uses-sdk android:minSdkVersion="14" />
+    <application android:label="Compute Perf">
+        <activity android:name="ComputePerf">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/RenderScriptTests/ComputePerf/res/layout/main.xml b/tests/RenderScriptTests/ComputePerf/res/layout/main.xml
new file mode 100644
index 0000000..61cd24d
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/res/layout/main.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+    <ImageView
+        android:id="@+id/displayin"
+        android:layout_width="320dip"
+        android:layout_height="266dip" />
+
+    <ImageView
+        android:id="@+id/displayout"
+        android:layout_width="320dip"
+        android:layout_height="266dip" />
+
+</LinearLayout>
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/ComputePerf.java b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/ComputePerf.java
new file mode 100644
index 0000000..d0e089b
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/ComputePerf.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.rs.computeperf;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap;
+import android.renderscript.RenderScript;
+import android.renderscript.Allocation;
+import android.widget.ImageView;
+
+public class ComputePerf extends Activity {
+
+    private LaunchTest mLT;
+    private RenderScript mRS;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+
+        mRS = RenderScript.create(this);
+        mLT = new LaunchTest(mRS, getResources());
+        mLT.run();
+        mLT.run();
+    }
+
+}
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/LaunchTest.java b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/LaunchTest.java
new file mode 100644
index 0000000..0c29ce1
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/LaunchTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.rs.computeperf;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class LaunchTest implements Runnable {
+    private RenderScript mRS;
+    private Allocation mAllocationX;
+    private Allocation mAllocationXY;
+    private ScriptC_launchtestxlw mScript_xlw;
+    private ScriptC_launchtestxyw mScript_xyw;
+
+    LaunchTest(RenderScript rs, Resources res) {
+        mRS = rs;
+        mScript_xlw = new ScriptC_launchtestxlw(mRS, res, R.raw.launchtestxlw);
+        mScript_xyw = new ScriptC_launchtestxyw(mRS, res, R.raw.launchtestxyw);
+        final int dim = mScript_xlw.get_dim();
+
+        mAllocationX = Allocation.createSized(rs, Element.U8(rs), dim);
+        Type.Builder tb = new Type.Builder(rs, Element.U8(rs));
+        tb.setX(dim);
+        tb.setY(dim);
+        mAllocationXY = Allocation.createTyped(rs, tb.create());
+        mScript_xlw.bind_buf(mAllocationXY);
+    }
+
+    public void run() {
+        long t = java.lang.System.currentTimeMillis();
+        mScript_xlw.forEach_root(mAllocationX);
+        mRS.finish();
+        t = java.lang.System.currentTimeMillis() - t;
+        android.util.Log.v("ComputePerf", "xlw launch test  ms " + t);
+
+        t = java.lang.System.currentTimeMillis();
+        mScript_xyw.forEach_root(mAllocationXY);
+        mRS.finish();
+        t = java.lang.System.currentTimeMillis() - t;
+        android.util.Log.v("ComputePerf", "xyw launch test  ms " + t);
+    }
+
+}
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxlw.rs b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxlw.rs
new file mode 100644
index 0000000..7b81dfe
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxlw.rs
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.example.android.rs.computeperf)
+
+const int dim = 2048;
+uint8_t *buf;
+
+void root(uchar *v_out, uint32_t x) {
+    uint8_t *p = buf;
+    p += x * dim;
+    for (int i=0; i<dim; i++) {
+        p[i] = 1;
+    }
+}
+
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxyw.rs b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxyw.rs
new file mode 100644
index 0000000..7f7aa95
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxyw.rs
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.example.android.rs.computeperf)
+
+void root(uchar *v_out, uint32_t x, uint32_t y) {
+    *v_out = 0;
+}
+
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs
index b77ccb4..42b1cf1 100644
--- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs
+++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs
@@ -105,8 +105,8 @@
         rsgMeshComputeBoundingBox(info->mMesh,
                                   &minX, &minY, &minZ,
                                   &maxX, &maxY, &maxZ);
-        info->bBoxMin = (minX, minY, minZ);
-        info->bBoxMax = (maxX, maxY, maxZ);
+        info->bBoxMin = (float3){minX, minY, minZ};
+        info->bBoxMax = (float3){maxX, maxY, maxZ};
         gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f;
     }
     gLookAt = gLookAt / (float)size;
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs
index d44fd2b..05ef3ac 100644
--- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs
+++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs
@@ -104,8 +104,8 @@
         rsgMeshComputeBoundingBox(info->mMesh,
                                   &minX, &minY, &minZ,
                                   &maxX, &maxY, &maxZ);
-        info->bBoxMin = (minX, minY, minZ);
-        info->bBoxMax = (maxX, maxY, maxZ);
+        info->bBoxMin = (float3){minX, minY, minZ};
+        info->bBoxMax = (float3){maxX, maxY, maxZ};
         gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f;
     }
     gLookAt = gLookAt / (float)size;
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
index c038478..4466e59 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
@@ -64,6 +64,9 @@
 
         unitTests = new ArrayList<UnitTest>();
 
+        unitTests.add(new UT_sampler(this, mRes, mCtx));
+        unitTests.add(new UT_program_store(this, mRes, mCtx));
+        unitTests.add(new UT_program_raster(this, mRes, mCtx));
         unitTests.add(new UT_primitives(this, mRes, mCtx));
         unitTests.add(new UT_vector(this, mRes, mCtx));
         unitTests.add(new UT_rsdebug(this, mRes, mCtx));
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java
new file mode 100644
index 0000000..1fbf97a
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.ProgramRaster;
+import android.renderscript.ProgramRaster.CullMode;
+
+public class UT_program_raster extends UnitTest {
+    private Resources mRes;
+
+    protected UT_program_raster(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "ProgramRaster", ctx);
+        mRes = res;
+    }
+
+    private ProgramRaster.Builder getDefaultBuilder(RenderScript RS) {
+        ProgramRaster.Builder b = new ProgramRaster.Builder(RS);
+        b.setCullMode(CullMode.BACK);
+        b.setPointSpriteEnabled(false);
+        return b;
+    }
+
+    private void initializeGlobals(RenderScript RS, ScriptC_program_raster s) {
+        ProgramRaster.Builder b = getDefaultBuilder(RS);
+        s.set_pointSpriteEnabled(b.setPointSpriteEnabled(true).create());
+        b = getDefaultBuilder(RS);
+        s.set_cullMode(b.setCullMode(CullMode.FRONT).create());
+        return;
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        ScriptC_program_raster s = new ScriptC_program_raster(pRS, mRes, R.raw.program_raster);
+        pRS.setMessageHandler(mRsMessage);
+        initializeGlobals(pRS, s);
+        s.invoke_program_raster_test();
+        pRS.finish();
+        waitForMessage();
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java
new file mode 100644
index 0000000..e06112c
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.ProgramStore.BlendDstFunc;
+import android.renderscript.ProgramStore.BlendSrcFunc;
+import android.renderscript.ProgramStore.Builder;
+import android.renderscript.ProgramStore.DepthFunc;
+
+public class UT_program_store extends UnitTest {
+    private Resources mRes;
+
+    protected UT_program_store(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "ProgramStore", ctx);
+        mRes = res;
+    }
+
+    private ProgramStore.Builder getDefaultBuilder(RenderScript RS) {
+        ProgramStore.Builder b = new ProgramStore.Builder(RS);
+        b.setBlendFunc(ProgramStore.BlendSrcFunc.ZERO, ProgramStore.BlendDstFunc.ZERO);
+        b.setColorMaskEnabled(false, false, false, false);
+        b.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
+        b.setDepthMaskEnabled(false);
+        b.setDitherEnabled(false);
+        return b;
+    }
+
+    private void initializeGlobals(RenderScript RS, ScriptC_program_store s) {
+        ProgramStore.Builder b = getDefaultBuilder(RS);
+        s.set_ditherEnable(b.setDitherEnabled(true).create());
+
+        b = getDefaultBuilder(RS);
+        s.set_colorRWriteEnable(b.setColorMaskEnabled(true,  false, false, false).create());
+
+        b = getDefaultBuilder(RS);
+        s.set_colorGWriteEnable(b.setColorMaskEnabled(false, true,  false, false).create());
+
+        b = getDefaultBuilder(RS);
+        s.set_colorBWriteEnable(b.setColorMaskEnabled(false, false, true,  false).create());
+
+        b = getDefaultBuilder(RS);
+        s.set_colorAWriteEnable(b.setColorMaskEnabled(false, false, false, true).create());
+
+        b = getDefaultBuilder(RS);
+        s.set_blendSrc(b.setBlendFunc(ProgramStore.BlendSrcFunc.DST_COLOR,
+                                      ProgramStore.BlendDstFunc.ZERO).create());
+
+        b = getDefaultBuilder(RS);
+        s.set_blendDst(b.setBlendFunc(ProgramStore.BlendSrcFunc.ZERO,
+                                      ProgramStore.BlendDstFunc.DST_ALPHA).create());
+
+        b = getDefaultBuilder(RS);
+        s.set_depthWriteEnable(b.setDepthMaskEnabled(true).create());
+
+        b = getDefaultBuilder(RS);
+        s.set_depthFunc(b.setDepthFunc(ProgramStore.DepthFunc.GREATER).create());
+        return;
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        ScriptC_program_store s = new ScriptC_program_store(pRS, mRes, R.raw.program_store);
+        pRS.setMessageHandler(mRsMessage);
+        initializeGlobals(pRS, s);
+        s.invoke_program_store_test();
+        pRS.finish();
+        waitForMessage();
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java
new file mode 100644
index 0000000..b0ccf9d
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.Sampler;
+import android.renderscript.Sampler.Value;
+
+public class UT_sampler extends UnitTest {
+    private Resources mRes;
+
+    protected UT_sampler(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "Sampler", ctx);
+        mRes = res;
+    }
+
+    private Sampler.Builder getDefaultBuilder(RenderScript RS) {
+        Sampler.Builder b = new Sampler.Builder(RS);
+        b.setMinification(Value.NEAREST);
+        b.setMagnification(Value.NEAREST);
+        b.setWrapS(Value.CLAMP);
+        b.setWrapT(Value.CLAMP);
+        b.setAnisotropy(1.0f);
+        return b;
+    }
+
+    private void initializeGlobals(RenderScript RS, ScriptC_sampler s) {
+        Sampler.Builder b = getDefaultBuilder(RS);
+        b.setMinification(Value.LINEAR_MIP_LINEAR);
+        s.set_minification(b.create());
+
+        b = getDefaultBuilder(RS);
+        b.setMagnification(Value.LINEAR);
+        s.set_magnification(b.create());
+
+        b = getDefaultBuilder(RS);
+        b.setWrapS(Value.WRAP);
+        s.set_wrapS(b.create());
+
+        b = getDefaultBuilder(RS);
+        b.setWrapT(Value.WRAP);
+        s.set_wrapT(b.create());
+
+        b = getDefaultBuilder(RS);
+        b.setAnisotropy(8.0f);
+        s.set_anisotropy(b.create());
+        return;
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        ScriptC_sampler s = new ScriptC_sampler(pRS, mRes, R.raw.sampler);
+        pRS.setMessageHandler(mRsMessage);
+        initializeGlobals(pRS, s);
+        s.invoke_sampler_test();
+        pRS.finish();
+        waitForMessage();
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
new file mode 100644
index 0000000..11b8c30
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
@@ -0,0 +1,37 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_program_raster pointSpriteEnabled;
+rs_program_raster cullMode;
+
+static bool test_program_raster_getters() {
+    bool failed = false;
+
+    _RS_ASSERT(rsgProgramRasterGetPointSpriteEnabled(pointSpriteEnabled) == true);
+    _RS_ASSERT(rsgProgramRasterGetCullMode(pointSpriteEnabled) == RS_CULL_BACK);
+
+    _RS_ASSERT(rsgProgramRasterGetPointSpriteEnabled(cullMode) == false);
+    _RS_ASSERT(rsgProgramRasterGetCullMode(cullMode) == RS_CULL_FRONT);
+
+    if (failed) {
+        rsDebug("test_program_raster_getters FAILED", 0);
+    }
+    else {
+        rsDebug("test_program_raster_getters PASSED", 0);
+    }
+
+    return failed;
+}
+
+void program_raster_test() {
+    bool failed = false;
+    failed |= test_program_raster_getters();
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
new file mode 100644
index 0000000..3cd8a20
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
@@ -0,0 +1,128 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_program_store ditherEnable;
+rs_program_store colorRWriteEnable;
+rs_program_store colorGWriteEnable;
+rs_program_store colorBWriteEnable;
+rs_program_store colorAWriteEnable;
+rs_program_store blendSrc;
+rs_program_store blendDst;
+rs_program_store depthWriteEnable;
+rs_program_store depthFunc;
+
+static bool test_program_store_getters() {
+    bool failed = false;
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(depthFunc) == RS_DEPTH_FUNC_GREATER);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthFunc) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthFunc) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(depthWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(depthWriteEnable) == true);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(depthWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(depthWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(depthWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(depthWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(depthWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthWriteEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthWriteEnable) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorRWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(colorRWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorRWriteEnable) == true);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorRWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorRWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorRWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorRWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorRWriteEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorRWriteEnable) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorGWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(colorGWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorGWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorGWriteEnable) == true);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorGWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorGWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorGWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorGWriteEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorGWriteEnable) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorBWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(colorBWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorBWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorBWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorBWriteEnable) == true);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorBWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorBWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorBWriteEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorBWriteEnable) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorAWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(colorAWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorAWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorAWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorAWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorAWriteEnable) == true);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorAWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorAWriteEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorAWriteEnable) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(ditherEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(ditherEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(ditherEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(ditherEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(ditherEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(ditherEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(ditherEnable) == true);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(ditherEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(ditherEnable) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(blendSrc) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendSrc) == RS_BLEND_SRC_DST_COLOR);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendSrc) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(blendDst) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendDst) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendDst) == RS_BLEND_DST_DST_ALPHA);
+
+    if (failed) {
+        rsDebug("test_program_store_getters FAILED", 0);
+    }
+    else {
+        rsDebug("test_program_store_getters PASSED", 0);
+    }
+
+    return failed;
+}
+
+void program_store_test() {
+    bool failed = false;
+    failed |= test_program_store_getters();
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs
new file mode 100644
index 0000000..ac9a549
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs
@@ -0,0 +1,63 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+rs_sampler minification;
+rs_sampler magnification;
+rs_sampler wrapS;
+rs_sampler wrapT;
+rs_sampler anisotropy;
+
+static bool test_sampler_getters() {
+    bool failed = false;
+
+    _RS_ASSERT(rsgSamplerGetMagnification(minification) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetMinification(minification) == RS_SAMPLER_LINEAR_MIP_LINEAR);
+    _RS_ASSERT(rsgSamplerGetWrapS(minification) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetWrapT(minification) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetAnisotropy(minification) == 1.0f);
+
+    _RS_ASSERT(rsgSamplerGetMagnification(magnification) == RS_SAMPLER_LINEAR);
+    _RS_ASSERT(rsgSamplerGetMinification(magnification) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetWrapS(magnification) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetWrapT(magnification) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetAnisotropy(magnification) == 1.0f);
+
+    _RS_ASSERT(rsgSamplerGetMagnification(wrapS) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetMinification(wrapS) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetWrapS(wrapS) == RS_SAMPLER_WRAP);
+    _RS_ASSERT(rsgSamplerGetWrapT(wrapS) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetAnisotropy(wrapS) == 1.0f);
+
+    _RS_ASSERT(rsgSamplerGetMagnification(wrapT) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetMinification(wrapT) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetWrapS(wrapT) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetWrapT(wrapT) == RS_SAMPLER_WRAP);
+    _RS_ASSERT(rsgSamplerGetAnisotropy(wrapT) == 1.0f);
+
+    _RS_ASSERT(rsgSamplerGetMagnification(anisotropy) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetMinification(anisotropy) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetWrapS(anisotropy) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetWrapT(anisotropy) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetAnisotropy(anisotropy) == 8.0f);
+
+    if (failed) {
+        rsDebug("test_sampler_getters FAILED", 0);
+    }
+    else {
+        rsDebug("test_sampler_getters PASSED", 0);
+    }
+
+    return failed;
+}
+
+void sampler_test() {
+    bool failed = false;
+    failed |= test_sampler_getters();
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+