Merge "Add Japanese specific key codes."
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ab4e73d..98c4e10 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -174,8 +174,10 @@
     static final ThreadLocal<ActivityThread> sThreadLocal = new ThreadLocal<ActivityThread>();
     Instrumentation mInstrumentation;
     String mInstrumentationAppDir = null;
+    String mInstrumentationAppLibraryDir = null;
     String mInstrumentationAppPackage = null;
     String mInstrumentedAppDir = null;
+    String mInstrumentedAppLibraryDir = null;
     boolean mSystemThread = false;
     boolean mJitEnabled = false;
 
@@ -3936,8 +3938,10 @@
             }
 
             mInstrumentationAppDir = ii.sourceDir;
+            mInstrumentationAppLibraryDir = ii.nativeLibraryDir;
             mInstrumentationAppPackage = ii.packageName;
             mInstrumentedAppDir = data.info.getAppDir();
+            mInstrumentedAppLibraryDir = data.info.getLibDir();
 
             ApplicationInfo instrApp = new ApplicationInfo();
             instrApp.packageName = ii.packageName;
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 5340fbb..8ab1ed6 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -261,6 +261,7 @@
 
             if (mIncludeCode && !mPackageName.equals("android")) {
                 String zip = mAppDir;
+                String libraryPath = mLibDir;
 
                 /*
                  * The following is a bit of a hack to inject
@@ -273,15 +274,20 @@
 
                 String instrumentationAppDir =
                         mActivityThread.mInstrumentationAppDir;
+                String instrumentationAppLibraryDir =
+                        mActivityThread.mInstrumentationAppLibraryDir;
                 String instrumentationAppPackage =
                         mActivityThread.mInstrumentationAppPackage;
                 String instrumentedAppDir =
                         mActivityThread.mInstrumentedAppDir;
+                String instrumentedAppLibraryDir =
+                        mActivityThread.mInstrumentedAppLibraryDir;
                 String[] instrumentationLibs = null;
 
                 if (mAppDir.equals(instrumentationAppDir)
                         || mAppDir.equals(instrumentedAppDir)) {
                     zip = instrumentationAppDir + ":" + instrumentedAppDir;
+                    libraryPath = instrumentationAppLibraryDir + ":" + instrumentedAppLibraryDir;
                     if (! instrumentedAppDir.equals(instrumentationAppDir)) {
                         instrumentationLibs =
                             getLibrariesFor(instrumentationAppPackage);
@@ -301,7 +307,7 @@
                  */
 
                 if (ActivityThread.localLOGV)
-                    Slog.v(ActivityThread.TAG, "Class path: " + zip + ", JNI path: " + mLibDir);
+                    Slog.v(ActivityThread.TAG, "Class path: " + zip + ", JNI path: " + libraryPath);
 
                 // Temporarily disable logging of disk reads on the Looper thread
                 // as this is early and necessary.
@@ -309,7 +315,7 @@
 
                 mClassLoader =
                     ApplicationLoaders.getDefault().getClassLoader(
-                        zip, mLibDir, mBaseClassLoader);
+                        zip, libraryPath, mBaseClassLoader);
                 initializeJavaContextClassLoader();
 
                 StrictMode.setThreadPolicy(oldPolicy);
@@ -442,6 +448,10 @@
         return mAppDir;
     }
 
+    public String getLibDir() {
+        return mLibDir;
+    }
+
     public String getResDir() {
         return mResDir;
     }
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index b816b11..4aa7fe2 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -16,9 +16,6 @@
 
 package android.os;
 
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
 import android.util.TimeUtils;
 
 /**
@@ -368,13 +365,13 @@
      *
      * Asynchronous messages represent interrupts or events that do not require global ordering
      * with represent to synchronous messages.  Asynchronous messages are not subject to
-     * the synchronization barriers introduced by {@link MessageQueue#acquireSyncBarrier()}.
+     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
      *
      * @return True if the message is asynchronous.
      *
      * @see #setAsynchronous(boolean)
-     * @see MessageQueue#acquireSyncBarrier()
-     * @see MessageQueue#releaseSyncBarrier()
+     * @see MessageQueue#enqueueSyncBarrier(long)
+     * @see MessageQueue#removeSyncBarrier(int)
      *
      * @hide
      */
@@ -387,13 +384,13 @@
      *
      * Asynchronous messages represent interrupts or events that do not require global ordering
      * with represent to synchronous messages.  Asynchronous messages are not subject to
-     * the synchronization barriers introduced by {@link MessageQueue#acquireSyncBarrier()}.
+     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
      *
      * @param async True if the message is asynchronous.
      *
      * @see #isAsynchronous()
-     * @see MessageQueue#acquireSyncBarrier()
-     * @see MessageQueue#releaseSyncBarrier()
+     * @see MessageQueue#enqueueSyncBarrier(long)
+     * @see MessageQueue#removeSyncBarrier(int)
      *
      * @hide
      */
@@ -506,7 +503,7 @@
         Messenger.writeMessengerOrNullToParcel(replyTo, dest);
     }
 
-    private final void readFromParcel(Parcel source) {
+    private void readFromParcel(Parcel source) {
         what = source.readInt();
         arg1 = source.readInt();
         arg2 = source.readInt();
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index d0c87c6..f7a7eb8 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -262,19 +262,8 @@
         return append(String.valueOf(text));
     }
 
-    private int change(int start, int end, CharSequence tb, int tbstart, int tbend) {
-        return change(true, start, end, tb, tbstart, tbend);
-    }
-
-    private int change(boolean notify, int start, int end,
-                       CharSequence tb, int tbstart, int tbend) {
+    private void change(int start, int end, CharSequence tb, int tbstart, int tbend) {
         checkRange("replace", start, end);
-        int ret = tbend - tbstart;
-        TextWatcher[] recipients = null;
-
-        if (notify) {
-            recipients = sendTextWillChange(start, end - start, tbend - tbstart);
-        }
 
         for (int i = mSpanCount - 1; i >= 0; i--) {
             if ((mSpanFlags[i] & SPAN_PARAGRAPH) == SPAN_PARAGRAPH) {
@@ -338,7 +327,7 @@
                     en = tbend;
 
                 if (getSpanStart(spans[i]) < 0) {
-                    setSpan(true, spans[i],
+                    setSpan(false, spans[i],
                             st - tbstart + start,
                             en - tbstart + start,
                             sp.getSpanFlags(spans[i]));
@@ -346,51 +335,37 @@
             }
         }
 
-        // no need for span fixup on pure insertion
-        if (tbend > tbstart && end - start == 0) {
-            if (notify) {
-                sendTextChange(recipients, start, end - start, tbend - tbstart);
-                sendTextHasChanged(recipients);
-            }
+        if (end > start) {
+            // no need for span fixup on pure insertion
+            boolean atEnd = (mGapStart + mGapLength == mText.length);
 
-            return ret;
-        }
+            for (int i = mSpanCount - 1; i >= 0; i--) {
+                if (mSpanStarts[i] >= start &&
+                        mSpanStarts[i] < mGapStart + mGapLength) {
+                    int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT;
 
-        boolean atend = (mGapStart + mGapLength == mText.length);
-
-        for (int i = mSpanCount - 1; i >= 0; i--) {
-            if (mSpanStarts[i] >= start &&
-                mSpanStarts[i] < mGapStart + mGapLength) {
-                int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT;
-
-                if (flag == POINT || (flag == PARAGRAPH && atend))
+                if (flag == POINT || (flag == PARAGRAPH && atEnd))
                     mSpanStarts[i] = mGapStart + mGapLength;
                 else
                     mSpanStarts[i] = start;
-            }
+                }
 
-            if (mSpanEnds[i] >= start &&
-                mSpanEnds[i] < mGapStart + mGapLength) {
-                int flag = (mSpanFlags[i] & END_MASK);
+                if (mSpanEnds[i] >= start &&
+                        mSpanEnds[i] < mGapStart + mGapLength) {
+                    int flag = (mSpanFlags[i] & END_MASK);
 
-                if (flag == POINT || (flag == PARAGRAPH && atend))
-                    mSpanEnds[i] = mGapStart + mGapLength;
-                else
-                    mSpanEnds[i] = start;
-            }
+                    if (flag == POINT || (flag == PARAGRAPH && atEnd))
+                        mSpanEnds[i] = mGapStart + mGapLength;
+                    else
+                        mSpanEnds[i] = start;
+                }
 
-            // remove 0-length SPAN_EXCLUSIVE_EXCLUSIVE
-            if (mSpanEnds[i] < mSpanStarts[i]) {
-                removeSpan(i);
+                // remove 0-length SPAN_EXCLUSIVE_EXCLUSIVE
+                if (mSpanEnds[i] < mSpanStarts[i]) {
+                    removeSpan(i);
+                }
             }
         }
-
-        if (notify) {
-            sendTextChange(recipients, start, end - start, tbend - tbstart);
-            sendTextHasChanged(recipients);
-        }
-
-        return ret;
     }
 
     private void removeSpan(int i) {
@@ -425,8 +400,7 @@
                         CharSequence tb, int tbstart, int tbend) {
         int filtercount = mFilters.length;
         for (int i = 0; i < filtercount; i++) {
-            CharSequence repl = mFilters[i].filter(tb, tbstart, tbend,
-                                                   this, start, end);
+            CharSequence repl = mFilters[i].filter(tb, tbstart, tbend, this, start, end);
 
             if (repl != null) {
                 tb = repl;
@@ -435,11 +409,17 @@
             }
         }
 
-        if (end == start && tbstart == tbend) {
+        final int origLen = end - start;
+        final int newLen = tbend - tbstart;
+
+        if (origLen == 0 && newLen == 0) {
             return this;
         }
 
-        if (end == start || tbstart == tbend) {
+        TextWatcher[] textWatchers = getSpans(start, start + origLen, TextWatcher.class);
+        sendBeforeTextChanged(textWatchers, start, origLen, newLen);
+
+        if (origLen == 0 || newLen == 0) {
             change(start, end, tb, tbstart, tbend);
         } else {
             int selstart = Selection.getSelectionStart(this);
@@ -450,11 +430,6 @@
 
             checkRange("replace", start, end);
             moveGapTo(end);
-            TextWatcher[] recipients;
-
-            int origlen = end - start;
-
-            recipients = sendTextWillChange(start, origlen, tbend - tbstart);
 
             if (mGapLength < 2)
                 resizeFor(length() + 1);
@@ -475,9 +450,9 @@
                 new Exception("mGapLength < 1").printStackTrace();
             }
 
-            int inserted = change(false, start + 1, start + 1, tb, tbstart, tbend);
-            change(false, start, start + 1, "", 0, 0);
-            change(false, start + inserted, start + inserted + origlen, "", 0, 0);
+            change(start + 1, start + 1, tb, tbstart, tbend);
+            change(start, start + 1, "", 0, 0);
+            change(start + newLen, start + newLen + origLen, "", 0, 0);
 
             /*
              * Special case to keep the cursor in the same position
@@ -490,7 +465,7 @@
             if (selstart > start && selstart < end) {
                 long off = selstart - start;
 
-                off = off * inserted / (end - start);
+                off = off * newLen / (end - start);
                 selstart = (int) off + start;
 
                 setSpan(false, Selection.SELECTION_START, selstart, selstart,
@@ -499,15 +474,16 @@
             if (selend > start && selend < end) {
                 long off = selend - start;
 
-                off = off * inserted / (end - start);
+                off = off * newLen / (end - start);
                 selend = (int) off + start;
 
                 setSpan(false, Selection.SELECTION_END, selend, selend, Spanned.SPAN_POINT_POINT);
             }
-            sendTextChange(recipients, start, origlen, inserted);
-            sendTextHasChanged(recipients);
         }
 
+        sendTextChanged(textWatchers, start, origLen, newLen);
+        sendAfterTextChanged(textWatchers);
+
         return this; 
     }
 
@@ -872,30 +848,27 @@
         return new String(buf);
     }
 
-    private TextWatcher[] sendTextWillChange(int start, int before, int after) {
-        TextWatcher[] recip = getSpans(start, start + before, TextWatcher.class);
-        int n = recip.length;
+    private void sendBeforeTextChanged(TextWatcher[] watchers, int start, int before, int after) {
+        int n = watchers.length;
 
         for (int i = 0; i < n; i++) {
-            recip[i].beforeTextChanged(this, start, before, after);
-        }
-
-        return recip;
-    }
-
-    private void sendTextChange(TextWatcher[] recip, int start, int before, int after) {
-        int n = recip.length;
-
-        for (int i = 0; i < n; i++) {
-            recip[i].onTextChanged(this, start, before, after);
+            watchers[i].beforeTextChanged(this, start, before, after);
         }
     }
 
-    private void sendTextHasChanged(TextWatcher[] recip) {
-        int n = recip.length;
+    private void sendTextChanged(TextWatcher[] watchers, int start, int before, int after) {
+        int n = watchers.length;
 
         for (int i = 0; i < n; i++) {
-            recip[i].afterTextChanged(this);
+            watchers[i].onTextChanged(this, start, before, after);
+        }
+    }
+
+    private void sendAfterTextChanged(TextWatcher[] watchers) {
+        int n = watchers.length;
+
+        for (int i = 0; i < n; i++) {
+            watchers[i].afterTextChanged(this);
         }
     }
 
@@ -1037,8 +1010,7 @@
      * Don't call this yourself -- exists for Canvas to use internally.
      * {@hide}
      */
-    public void drawText(Canvas c, int start, int end,
-                         float x, float y, Paint p) {
+    public void drawText(Canvas c, int start, int end, float x, float y, Paint p) {
         checkRange("drawText", start, end);
 
         if (end <= mGapStart) {
@@ -1059,8 +1031,7 @@
      * Don't call this yourself -- exists for Canvas to use internally.
      * {@hide}
      */
-    public void drawTextRun(Canvas c, int start, int end,
-            int contextStart, int contextEnd,
+    public void drawTextRun(Canvas c, int start, int end, int contextStart, int contextEnd,
             float x, float y, int flags, Paint p) {
         checkRange("drawTextRun", start, end);
 
@@ -1262,6 +1233,7 @@
     private int[] mSpanFlags;
     private int mSpanCount;
 
+    // TODO These value are tightly related to the public SPAN_MARK/POINT values in {@link Spanned}
     private static final int POINT = 2;
     private static final int PARAGRAPH = 3;
 
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index e2aafa9..33631b7 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import android.graphics.Matrix;
+
 /**
  * A display lists records a series of graphics related operation and can replay
  * them later. Display lists are usually built by recording operations on a
@@ -117,12 +119,26 @@
     public abstract void setClipChildren(boolean clipChildren);
 
     /**
-     * Set the application scale on the DisplayList. This scale is incurred by applications that
-     * are auto-scaled for compatibility reasons. By default, the value is 1 (unscaled).
+     * Set the static matrix on the DisplayList. This matrix exists if a custom ViewGroup
+     * overrides
+     * {@link ViewGroup#getChildStaticTransformation(View, android.view.animation.Transformation)}
+     * and also has {@link ViewGroup#setStaticTransformationsEnabled(boolean)} set to true.
+     * This matrix will be concatenated with any other matrices in the DisplayList to position
+     * the view appropriately.
      *
-     * @param scale The scaling factor
+     * @param matrix The matrix
      */
-    public abstract void setApplicationScale(float scale);
+    public abstract void setStaticMatrix(Matrix matrix);
+
+    /**
+     * Set the Animation matrix on the DisplayList. This matrix exists if an Animation is
+     * currently playing on a View, and is set on the DisplayList during at draw() time. When
+     * the Animation finishes, the matrix should be cleared by sending <code>null</code>
+     * for the matrix parameter.
+     *
+     * @param matrix The matrix, null indicates that the matrix should be cleared.
+     */
+    public abstract void setAnimationMatrix(Matrix matrix);
 
     /**
      * Sets the alpha value for the DisplayList
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 5b0433e..bedafc7 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -259,6 +259,13 @@
 
     private static native int nCallDrawGLFunction(int renderer, int drawGLFunction);
 
+    @Override
+    public int invokeFunctors(Rect dirty) {
+        return nInvokeFunctors(mRenderer, dirty);
+    }
+
+    private static native int nInvokeFunctors(int renderer, Rect dirty);
+
     ///////////////////////////////////////////////////////////////////////////
     // Memory
     ///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index 9b4cf21..bc3bce0 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.graphics.Bitmap;
+import android.graphics.Matrix;
 
 import java.util.ArrayList;
 
@@ -119,9 +120,18 @@
     }
 
     @Override
-    public void setApplicationScale(float scale) {
+    public void setStaticMatrix(Matrix matrix) {
         try {
-            nSetApplicationScale(getNativeDisplayList(), scale);
+            nSetStaticMatrix(getNativeDisplayList(), matrix.native_instance);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setAnimationMatrix(Matrix matrix) {
+        try {
+            nSetAnimationMatrix(getNativeDisplayList(), matrix.native_instance);
         } catch (IllegalStateException e) {
             // invalid DisplayList okay: we'll set current values the next time we render to it
         }
@@ -335,6 +345,8 @@
     private static native void nSetTransformationInfo(int displayList, float alpha,
             float translationX, float translationY, float rotation, float rotationX,
             float rotationY, float scaleX, float scaleY);
+    private static native void nSetStaticMatrix(int displayList, int nativeMatrix);
+    private static native void nSetAnimationMatrix(int displayList, int animationMatrix);
 
 
     ///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index 2636ea2..de8c62d 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -98,4 +98,16 @@
         // Noop - this is done in the display list recorder subclass
         return DisplayList.STATUS_DONE;
     }
+
+    /**
+     * Invoke all the functors who requested to be invoked during the previous frame.
+     * 
+     * @param dirty The region to redraw when the functors return {@link DisplayList#STATUS_DRAW}
+     *              
+     * @return One of {@link DisplayList#STATUS_DONE}, {@link DisplayList#STATUS_DRAW} or
+     *         {@link DisplayList#STATUS_INVOKE}
+     */
+    public int invokeFunctors(Rect dirty) {
+        return DisplayList.STATUS_DONE;
+    }
 }
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 133f601..b100a0c 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -502,7 +502,9 @@
         static final int SURFACE_STATE_ERROR = 0;
         static final int SURFACE_STATE_SUCCESS = 1;
         static final int SURFACE_STATE_UPDATED = 2;
-        
+
+        static final int FUNCTOR_PROCESS_DELAY = 2;
+
         static EGL10 sEgl;
         static EGLDisplay sEglDisplay;
         static EGLConfig sEglConfig;
@@ -549,7 +551,9 @@
         private boolean mDestroyed;
 
         private final Rect mRedrawClip = new Rect();
+
         private final int[] mSurfaceSize = new int[2];
+        private final FunctorsRunnable mFunctorsRunnable = new FunctorsRunnable();
 
         GlRenderer(int glVersion, boolean translucent) {
             mGlVersion = glVersion;
@@ -957,6 +961,24 @@
         void onPostDraw() {
         }
 
+        class FunctorsRunnable implements Runnable {
+            View.AttachInfo attachInfo;
+
+            @Override
+            public void run() {
+                final HardwareRenderer renderer = attachInfo.mHardwareRenderer;
+                if (renderer == null || !renderer.isEnabled() || renderer != GlRenderer.this) {
+                    return;
+                }
+
+                final int surfaceState = checkCurrent();
+                if (surfaceState != SURFACE_STATE_ERROR) {
+                    int status = mCanvas.invokeFunctors(mRedrawClip);
+                    handleFunctorStatus(attachInfo, status);
+                }
+            }
+        }
+
         @Override
         boolean draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
                 Rect dirty) {
@@ -1051,15 +1073,7 @@
                                 }
                             }
 
-                            if (status != DisplayList.STATUS_DONE) {
-                                if (mRedrawClip.isEmpty()) {
-                                    attachInfo.mViewRootImpl.invalidate();
-                                } else {
-                                    attachInfo.mViewRootImpl.invalidateChildInParent(
-                                            null, mRedrawClip);
-                                    mRedrawClip.setEmpty();
-                                }
-                            }
+                            handleFunctorStatus(attachInfo, status);
                         } else {
                             // Shouldn't reach here
                             view.draw(canvas);
@@ -1111,6 +1125,26 @@
             return false;
         }
 
+        private void handleFunctorStatus(View.AttachInfo attachInfo, int status) {
+            // If the draw flag is set, functors will be invoked while executing
+            // the tree of display lists
+            if ((status & DisplayList.STATUS_DRAW) != 0) {
+                if (mRedrawClip.isEmpty()) {
+                    attachInfo.mViewRootImpl.invalidate();
+                } else {
+                    attachInfo.mViewRootImpl.invalidateChildInParent(null, mRedrawClip);
+                    mRedrawClip.setEmpty();
+                }
+            }
+
+            if ((status & DisplayList.STATUS_INVOKE) != 0) {
+                attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
+                mFunctorsRunnable.attachInfo = attachInfo;
+                // delay the functor callback by a few ms so it isn't polled constantly
+                attachInfo.mHandler.postDelayed(mFunctorsRunnable, FUNCTOR_PROCESS_DELAY);
+            }
+        }
+
         /**
          * Ensures the current EGL context is the one we expect.
          * 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 81f3f6a..18e1697 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1464,7 +1464,7 @@
      * apps.
      * @hide
      */
-    public static final boolean USE_DISPLAY_LIST_PROPERTIES = false;
+    public static final boolean USE_DISPLAY_LIST_PROPERTIES = true;
 
     /**
      * Map used to store views' tags.
@@ -11529,12 +11529,34 @@
                 displayList.setClipChildren(
                         (((ViewGroup)mParent).mGroupFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0);
             }
-            if (mAttachInfo != null && mAttachInfo.mScalingRequired &&
-                    mAttachInfo.mApplicationScale != 1.0f) {
-                displayList.setApplicationScale(1f / mAttachInfo.mApplicationScale);
+            float alpha = 1;
+            if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags &
+                    ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
+                ViewGroup parentVG = (ViewGroup) mParent;
+                final boolean hasTransform =
+                        parentVG.getChildStaticTransformation(this, parentVG.mChildTransformation);
+                if (hasTransform) {
+                    Transformation transform = parentVG.mChildTransformation;
+                    final int transformType = parentVG.mChildTransformation.getTransformationType();
+                    if (transformType != Transformation.TYPE_IDENTITY) {
+                        if ((transformType & Transformation.TYPE_ALPHA) != 0) {
+                            alpha = transform.getAlpha();
+                        }
+                        if ((transformType & Transformation.TYPE_MATRIX) != 0) {
+                            displayList.setStaticMatrix(transform.getMatrix());
+                        }
+                    }
+                }
             }
             if (mTransformationInfo != null) {
-                displayList.setTransformationInfo(mTransformationInfo.mAlpha,
+                alpha *= mTransformationInfo.mAlpha;
+                if (alpha < 1) {
+                    final int multipliedAlpha = (int) (255 * alpha);
+                    if (onSetAlpha(multipliedAlpha)) {
+                        alpha = 1;
+                    }
+                }
+                displayList.setTransformationInfo(alpha,
                         mTransformationInfo.mTranslationX, mTransformationInfo.mTranslationY,
                         mTransformationInfo.mRotation, mTransformationInfo.mRotationX,
                         mTransformationInfo.mRotationY, mTransformationInfo.mScaleX,
@@ -11548,6 +11570,8 @@
                     displayList.setPivotX(getPivotX());
                     displayList.setPivotY(getPivotY());
                 }
+            } else if (alpha < 1) {
+                displayList.setAlpha(alpha);
             }
         }
     }
@@ -11580,6 +11604,7 @@
         if ((flags & ViewGroup.FLAG_CHILDREN_DRAWN_WITH_CACHE) != 0 ||
                 (flags & ViewGroup.FLAG_ALWAYS_DRAWN_WITH_CACHE) != 0) {
             caching = true;
+            // Auto-scaled apps are not hw-accelerated, no need to set scaling flag on DisplayList
             if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
         } else {
             caching = (layerType != LAYER_TYPE_NONE) || hardwareAccelerated;
@@ -11590,7 +11615,8 @@
             more = drawAnimation(parent, drawingTime, a, scalingRequired);
             concatMatrix = a.willChangeTransformationMatrix();
             transformToApply = parent.mChildTransformation;
-        } else if ((flags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
+        } else if (!useDisplayListProperties &&
+                (flags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
             final boolean hasTransform =
                     parent.getChildStaticTransformation(this, parent.mChildTransformation);
             if (hasTransform) {
@@ -11658,6 +11684,17 @@
             }
         }
         useDisplayListProperties &= hasDisplayList;
+        if (useDisplayListProperties) {
+            displayList = getDisplayList();
+            if (!displayList.isValid()) {
+                // Uncommon, but possible. If a view is removed from the hierarchy during the call
+                // to getDisplayList(), the display list will be marked invalid and we should not
+                // try to use it again.
+                displayList = null;
+                hasDisplayList = false;
+                useDisplayListProperties = false;
+            }
+        }
 
         final boolean hasNoCache = cache == null || hasDisplayList;
         final boolean offsetForScroll = cache == null && !hasDisplayList &&
@@ -11675,6 +11712,7 @@
             }
             if (scalingRequired) {
                 if (useDisplayListProperties) {
+                    // TODO: Might not need this if we put everything inside the DL
                     restoreTo = canvas.save();
                 }
                 // mAttachInfo cannot be null, otherwise scalingRequired == false
@@ -11684,7 +11722,7 @@
         }
 
         float alpha = useDisplayListProperties ? 1 : getAlpha();
-        if (transformToApply != null || alpha < 1.0f || !hasIdentityMatrix()) {
+        if (transformToApply != null || alpha < 1 || !hasIdentityMatrix()) {
             if (transformToApply != null || !childHasIdentityMatrix) {
                 int transX = 0;
                 int transY = 0;
@@ -11696,16 +11734,20 @@
 
                 if (transformToApply != null) {
                     if (concatMatrix) {
-                        // Undo the scroll translation, apply the transformation matrix,
-                        // then redo the scroll translate to get the correct result.
-                        canvas.translate(-transX, -transY);
-                        canvas.concat(transformToApply.getMatrix());
-                        canvas.translate(transX, transY);
+                        if (useDisplayListProperties) {
+                            displayList.setAnimationMatrix(transformToApply.getMatrix());
+                        } else {
+                            // Undo the scroll translation, apply the transformation matrix,
+                            // then redo the scroll translate to get the correct result.
+                            canvas.translate(-transX, -transY);
+                            canvas.concat(transformToApply.getMatrix());
+                            canvas.translate(transX, transY);
+                        }
                         parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
                     }
 
                     float transformAlpha = transformToApply.getAlpha();
-                    if (transformAlpha < 1.0f) {
+                    if (transformAlpha < 1) {
                         alpha *= transformToApply.getAlpha();
                         parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
                     }
@@ -11718,7 +11760,7 @@
                 }
             }
 
-            if (alpha < 1.0f) {
+            if (alpha < 1) {
                 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
                 if (hasNoCache) {
                     final int multipliedAlpha = (int) (255 * alpha);
@@ -11728,7 +11770,9 @@
                                 layerType != LAYER_TYPE_NONE) {
                             layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
                         }
-                        if (layerType == LAYER_TYPE_NONE) {
+                        if (useDisplayListProperties) {
+                            displayList.setAlpha(alpha * getAlpha());
+                        } else  if (layerType == LAYER_TYPE_NONE) {
                             final int scrollX = hasDisplayList ? 0 : sx;
                             final int scrollY = hasDisplayList ? 0 : sy;
                             canvas.saveLayerAlpha(scrollX, scrollY, scrollX + mRight - mLeft,
@@ -11758,7 +11802,7 @@
             }
         }
 
-        if (hasDisplayList) {
+        if (!useDisplayListProperties && hasDisplayList) {
             displayList = getDisplayList();
             if (!displayList.isValid()) {
                 // Uncommon, but possible. If a view is removed from the hierarchy during the call
@@ -11815,7 +11859,7 @@
                     cachePaint.setDither(false);
                     parent.mCachePaint = cachePaint;
                 }
-                if (alpha < 1.0f) {
+                if (alpha < 1) {
                     cachePaint.setAlpha((int) (alpha * 255));
                     parent.mGroupFlags |= ViewGroup.FLAG_ALPHA_LOWER_THAN_ONE;
                 } else if  ((flags & ViewGroup.FLAG_ALPHA_LOWER_THAN_ONE) != 0) {
@@ -13614,13 +13658,12 @@
         mPrivateFlags |= FORCE_LAYOUT;
         mPrivateFlags |= INVALIDATED;
 
-        if (mParent != null) {
-            if (mLayoutParams != null) {
-                mLayoutParams.onResolveLayoutDirection(getResolvedLayoutDirection());
-            }
-            if (!mParent.isLayoutRequested()) {
-                mParent.requestLayout();
-            }
+        if (mLayoutParams != null) {
+            mLayoutParams.onResolveLayoutDirection(getResolvedLayoutDirection());
+        }
+
+        if (mParent != null && !mParent.isLayoutRequested()) {
+            mParent.requestLayout();
         }
     }
 
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 04fa07a..45c5fa0 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -1204,10 +1204,8 @@
     static final int SHOW_FULLSCREEN                    = 120;
     static final int HIDE_FULLSCREEN                    = 121;
     static final int REPLACE_BASE_CONTENT               = 123;
-    static final int FORM_DID_BLUR                      = 124;
     static final int UPDATE_MATCH_COUNT                 = 126;
     static final int CENTER_FIT_RECT                    = 127;
-    static final int REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID = 128;
     static final int SET_SCROLLBAR_MODES                = 129;
     static final int SELECTION_STRING_CHANGED           = 130;
     static final int HIT_TEST_RESULT                    = 131;
@@ -1274,7 +1272,6 @@
         "HIDE_FULLSCREEN", //                = 121;
         "DOM_FOCUS_CHANGED", //              = 122;
         "REPLACE_BASE_CONTENT", //           = 123;
-        "FORM_DID_BLUR", //                  = 124;
         "RETURN_LABEL", //                   = 125;
         "UPDATE_MATCH_COUNT", //             = 126;
         "CENTER_FIT_RECT", //                = 127;
@@ -8288,16 +8285,10 @@
                         }
                     }
                     break;
-                case REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID:
-                    displaySoftKeyboard(true);
-                    // fall through to UPDATE_TEXT_SELECTION_MSG_ID
                 case UPDATE_TEXT_SELECTION_MSG_ID:
                     updateTextSelectionFromMessage(msg.arg1, msg.arg2,
                             (WebViewCore.TextSelectionData) msg.obj);
                     break;
-                case FORM_DID_BLUR:
-                    // TODO: Figure out if this is needed for something (b/6111763)
-                    break;
                 case TAKE_FOCUS:
                     int direction = msg.arg1;
                     View focusSearch = mWebView.focusSearch(direction);
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 3eba6d7..b4ebc09 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -325,17 +325,6 @@
     }
 
     /**
-     * Called by JNI.  Send a message to the UI thread to hide the soft keyboard
-     * if the node pointed to by nodePointer is still in focus.
-     * @param nodePointer The node which just blurred.
-     */
-    private void formDidBlur(int nodePointer) {
-        if (mWebViewClassic == null) return;
-        Message.obtain(mWebViewClassic.mPrivateHandler, WebViewClassic.FORM_DID_BLUR,
-                nodePointer, 0).sendToTarget();
-    }
-
-    /**
      * Called by JNI when the focus node changed.
      */
     private void focusNodeChanged(int nodePointer, WebKitHitTest hitTest) {
@@ -2830,7 +2819,7 @@
         Message.obtain(mWebViewClassic.mPrivateHandler,
                 WebViewClassic.INIT_EDIT_FIELD, initData).sendToTarget();
         Message.obtain(mWebViewClassic.mPrivateHandler,
-                WebViewClassic.REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID,
+                WebViewClassic.UPDATE_TEXT_SELECTION_MSG_ID,
                 initData.mFieldPointer, 0,
                 new TextSelectionData(start, end, selectionPtr))
                 .sendToTarget();
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 586fdf4..8067435 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -477,8 +477,11 @@
         private static final String TAG = "FixedSizeRemoteViewsCache";
 
         // The meta data related to all the RemoteViews, ie. count, is stable, etc.
-        private RemoteViewsMetaData mMetaData;
-        private RemoteViewsMetaData mTemporaryMetaData;
+        // The meta data objects are made final so that they can be locked on independently
+        // of the FixedSizeRemoteViewsCache. If we ever lock on both meta data objects, it is in
+        // the order mTemporaryMetaData followed by mMetaData.
+        private final RemoteViewsMetaData mMetaData;
+        private final RemoteViewsMetaData mTemporaryMetaData;
 
         // The cache/mapping of position to RemoteViewsMetaData.  This set is guaranteed to be
         // greater than or equal to the set of RemoteViews.
@@ -939,6 +942,10 @@
      * which  wouldn't otherwise be possible.
      */
     public void setVisibleRangeHint(int lowerBound, int upperBound) {
+        if (lowerBound < 0 || upperBound < 0) {
+            throw new RuntimeException("Attempted to set invalid range: lowerBound="+lowerBound +
+                    "," + "upperBound="+upperBound);
+        }
         mVisibleWindowLowerBound = lowerBound;
         mVisibleWindowUpperBound = upperBound;
     }
@@ -1072,12 +1079,20 @@
 
         // Re-request the new metadata (only after the notification to the factory)
         updateTemporaryMetaData();
+        int newCount;
+        synchronized(mCache.getTemporaryMetaData()) {
+            newCount = mCache.getTemporaryMetaData().count;
+        }
 
         // Pre-load (our best guess of) the views which are currently visible in the AdapterView.
         // This mitigates flashing and flickering of loading views when a widget notifies that
         // its data has changed.
         for (int i = mVisibleWindowLowerBound; i <= mVisibleWindowUpperBound; i++) {
-            updateRemoteViews(i, false, false);
+            // Because temporary meta data is only ever modified from this thread (ie.
+            // mWorkerThread), it is safe to assume that count is a valid representation.
+            if (i < newCount) {
+                updateRemoteViews(i, false, false);
+            }
         }
 
         // Propagate the notification back to the base adapter
diff --git a/core/java/com/google/android/mms/pdu/PduPersister.java b/core/java/com/google/android/mms/pdu/PduPersister.java
index 7c937ed..1a8e80f 100644
--- a/core/java/com/google/android/mms/pdu/PduPersister.java
+++ b/core/java/com/google/android/mms/pdu/PduPersister.java
@@ -519,98 +519,99 @@
      * @throws MmsException Failed to load some fields of a PDU.
      */
     public GenericPdu load(Uri uri) throws MmsException {
-        PduCacheEntry cacheEntry;
-        synchronized(PDU_CACHE_INSTANCE) {
-            if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
-                if (LOCAL_LOGV) {
-                    Log.v(TAG, "load: " + uri + " blocked by isUpdating()");
-                }
-                try {
-                    PDU_CACHE_INSTANCE.wait();
-                } catch (InterruptedException e) {
-                    Log.e(TAG, "load: ", e);
-                }
-                cacheEntry = PDU_CACHE_INSTANCE.get(uri);
-                if (cacheEntry != null) {
-                    return cacheEntry.getPdu();
-                }
-            }
-            // Tell the cache to indicate to other callers that this item
-            // is currently being updated.
-            PDU_CACHE_INSTANCE.setUpdating(uri, true);
-        }
-
-        Cursor c = SqliteWrapper.query(mContext, mContentResolver, uri,
-                                                PDU_PROJECTION, null, null, null);
-        PduHeaders headers = new PduHeaders();
-        Set<Entry<Integer, Integer>> set;
-        long msgId = ContentUris.parseId(uri);
-        int msgBox;
-        long threadId;
-
-        try {
-            if ((c == null) || (c.getCount() != 1) || !c.moveToFirst()) {
-                throw new MmsException("Bad uri: " + uri);
-            }
-
-            msgBox = c.getInt(PDU_COLUMN_MESSAGE_BOX);
-            threadId = c.getLong(PDU_COLUMN_THREAD_ID);
-
-            set = ENCODED_STRING_COLUMN_INDEX_MAP.entrySet();
-            for (Entry<Integer, Integer> e : set) {
-                setEncodedStringValueToHeaders(
-                        c, e.getValue(), headers, e.getKey());
-            }
-
-            set = TEXT_STRING_COLUMN_INDEX_MAP.entrySet();
-            for (Entry<Integer, Integer> e : set) {
-                setTextStringToHeaders(
-                        c, e.getValue(), headers, e.getKey());
-            }
-
-            set = OCTET_COLUMN_INDEX_MAP.entrySet();
-            for (Entry<Integer, Integer> e : set) {
-                setOctetToHeaders(
-                        c, e.getValue(), headers, e.getKey());
-            }
-
-            set = LONG_COLUMN_INDEX_MAP.entrySet();
-            for (Entry<Integer, Integer> e : set) {
-                setLongToHeaders(
-                        c, e.getValue(), headers, e.getKey());
-            }
-        } finally {
-            if (c != null) {
-                c.close();
-            }
-        }
-
-        // Check whether 'msgId' has been assigned a valid value.
-        if (msgId == -1L) {
-            throw new MmsException("Error! ID of the message: -1.");
-        }
-
-        // Load address information of the MM.
-        loadAddress(msgId, headers);
-
-        int msgType = headers.getOctet(PduHeaders.MESSAGE_TYPE);
-        PduBody body = new PduBody();
-
-        // For PDU which type is M_retrieve.conf or Send.req, we should
-        // load multiparts and put them into the body of the PDU.
-        if ((msgType == PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF)
-                || (msgType == PduHeaders.MESSAGE_TYPE_SEND_REQ)) {
-            PduPart[] parts = loadParts(msgId);
-            if (parts != null) {
-                int partsNum = parts.length;
-                for (int i = 0; i < partsNum; i++) {
-                    body.addPart(parts[i]);
-                }
-            }
-        }
-
         GenericPdu pdu = null;
-        switch (msgType) {
+        PduCacheEntry cacheEntry = null;
+        int msgBox = 0;
+        long threadId = -1;
+        try {
+            synchronized(PDU_CACHE_INSTANCE) {
+                if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
+                    if (LOCAL_LOGV) {
+                        Log.v(TAG, "load: " + uri + " blocked by isUpdating()");
+                    }
+                    try {
+                        PDU_CACHE_INSTANCE.wait();
+                    } catch (InterruptedException e) {
+                        Log.e(TAG, "load: ", e);
+                    }
+                    cacheEntry = PDU_CACHE_INSTANCE.get(uri);
+                    if (cacheEntry != null) {
+                        return cacheEntry.getPdu();
+                    }
+                }
+                // Tell the cache to indicate to other callers that this item
+                // is currently being updated.
+                PDU_CACHE_INSTANCE.setUpdating(uri, true);
+            }
+
+            Cursor c = SqliteWrapper.query(mContext, mContentResolver, uri,
+                    PDU_PROJECTION, null, null, null);
+            PduHeaders headers = new PduHeaders();
+            Set<Entry<Integer, Integer>> set;
+            long msgId = ContentUris.parseId(uri);
+
+            try {
+                if ((c == null) || (c.getCount() != 1) || !c.moveToFirst()) {
+                    throw new MmsException("Bad uri: " + uri);
+                }
+
+                msgBox = c.getInt(PDU_COLUMN_MESSAGE_BOX);
+                threadId = c.getLong(PDU_COLUMN_THREAD_ID);
+
+                set = ENCODED_STRING_COLUMN_INDEX_MAP.entrySet();
+                for (Entry<Integer, Integer> e : set) {
+                    setEncodedStringValueToHeaders(
+                            c, e.getValue(), headers, e.getKey());
+                }
+
+                set = TEXT_STRING_COLUMN_INDEX_MAP.entrySet();
+                for (Entry<Integer, Integer> e : set) {
+                    setTextStringToHeaders(
+                            c, e.getValue(), headers, e.getKey());
+                }
+
+                set = OCTET_COLUMN_INDEX_MAP.entrySet();
+                for (Entry<Integer, Integer> e : set) {
+                    setOctetToHeaders(
+                            c, e.getValue(), headers, e.getKey());
+                }
+
+                set = LONG_COLUMN_INDEX_MAP.entrySet();
+                for (Entry<Integer, Integer> e : set) {
+                    setLongToHeaders(
+                            c, e.getValue(), headers, e.getKey());
+                }
+            } finally {
+                if (c != null) {
+                    c.close();
+                }
+            }
+
+            // Check whether 'msgId' has been assigned a valid value.
+            if (msgId == -1L) {
+                throw new MmsException("Error! ID of the message: -1.");
+            }
+
+            // Load address information of the MM.
+            loadAddress(msgId, headers);
+
+            int msgType = headers.getOctet(PduHeaders.MESSAGE_TYPE);
+            PduBody body = new PduBody();
+
+            // For PDU which type is M_retrieve.conf or Send.req, we should
+            // load multiparts and put them into the body of the PDU.
+            if ((msgType == PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF)
+                    || (msgType == PduHeaders.MESSAGE_TYPE_SEND_REQ)) {
+                PduPart[] parts = loadParts(msgId);
+                if (parts != null) {
+                    int partsNum = parts.length;
+                    for (int i = 0; i < partsNum; i++) {
+                        body.addPart(parts[i]);
+                    }
+                }
+            }
+
+            switch (msgType) {
             case PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND:
                 pdu = new NotificationInd(headers);
                 break;
@@ -657,16 +658,20 @@
             default:
                 throw new MmsException(
                         "Unrecognized PDU type: " + Integer.toHexString(msgType));
+            }
+        } finally {
+            synchronized(PDU_CACHE_INSTANCE) {
+                if (pdu != null) {
+                    assert(PDU_CACHE_INSTANCE.get(uri) == null);
+                    // Update the cache entry with the real info
+                    cacheEntry = new PduCacheEntry(pdu, msgBox, threadId);
+                    PDU_CACHE_INSTANCE.put(uri, cacheEntry);
+                }
+                PDU_CACHE_INSTANCE.setUpdating(uri, false);
+                PDU_CACHE_INSTANCE.notifyAll(); // tell anybody waiting on this entry to go ahead
+            }
         }
-
-        synchronized(PDU_CACHE_INSTANCE ) {
-            assert(PDU_CACHE_INSTANCE.get(uri) == null);
-            // Update the cache entry with the real info
-            cacheEntry = new PduCacheEntry(pdu, msgBox, threadId);
-            PDU_CACHE_INSTANCE.put(uri, cacheEntry);
-            PDU_CACHE_INSTANCE.notifyAll();     // tell anybody waiting on this entry to go ahead
-            return pdu;
-        }
+        return pdu;
     }
 
     private void persistAddress(
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index b472eef..6028814 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -163,6 +163,21 @@
     return renderer->callDrawGLFunction(functor, dirty);
 }
 
+static jint android_view_GLES20Canvas_invokeFunctors(JNIEnv* env,
+        jobject clazz, OpenGLRenderer* renderer, jobject dirty) {
+    android::uirenderer::Rect bounds;
+    status_t status = renderer->invokeFunctors(bounds);
+    if (status != DrawGlInfo::kStatusDone && dirty != NULL) {
+        env->CallVoidMethod(dirty, gRectClassInfo.set,
+                int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom));
+    }
+    return status;
+}
+
+// ----------------------------------------------------------------------------
+// Misc
+// ----------------------------------------------------------------------------
+
 static jint android_view_GLES20Canvas_getMaxTextureWidth(JNIEnv* env, jobject clazz) {
     return Caches::getInstance().maxTextureSize;
 }
@@ -824,6 +839,8 @@
     { "nGetStencilSize",    "()I",             (void*) android_view_GLES20Canvas_getStencilSize },
 
     { "nCallDrawGLFunction", "(II)I",          (void*) android_view_GLES20Canvas_callDrawGLFunction },
+    { "nInvokeFunctors",         "(ILandroid/graphics/Rect;)I",
+            (void*) android_view_GLES20Canvas_invokeFunctors },
 
     { "nSave",              "(II)I",           (void*) android_view_GLES20Canvas_save },
     { "nRestore",           "(I)V",            (void*) android_view_GLES20Canvas_restore },
@@ -899,9 +916,9 @@
     { "nDestroyDisplayList",     "(I)V",       (void*) android_view_GLES20Canvas_destroyDisplayList },
     { "nGetDisplayListSize",     "(I)I",       (void*) android_view_GLES20Canvas_getDisplayListSize },
     { "nSetDisplayListName",     "(ILjava/lang/String;)V",
-                                               (void*) android_view_GLES20Canvas_setDisplayListName },
+            (void*) android_view_GLES20Canvas_setDisplayListName },
     { "nDrawDisplayList",        "(IIIILandroid/graphics/Rect;I)I",
-                                               (void*) android_view_GLES20Canvas_drawDisplayList },
+            (void*) android_view_GLES20Canvas_drawDisplayList },
 
     { "nCreateDisplayListRenderer", "()I",     (void*) android_view_GLES20Canvas_createDisplayListRenderer },
     { "nResetDisplayListRenderer",  "(I)V",    (void*) android_view_GLES20Canvas_resetDisplayListRenderer },
diff --git a/core/jni/android_view_GLES20DisplayList.cpp b/core/jni/android_view_GLES20DisplayList.cpp
index 407c196..60fb6d4 100644
--- a/core/jni/android_view_GLES20DisplayList.cpp
+++ b/core/jni/android_view_GLES20DisplayList.cpp
@@ -45,9 +45,14 @@
     displayList->setCaching(caching);
 }
 
-static void android_view_GLES20DisplayList_setApplicationScale(JNIEnv* env,
-        jobject clazz, DisplayList* displayList, float scale) {
-    displayList->setApplicationScale(scale);
+static void android_view_GLES20DisplayList_setStaticMatrix(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, SkMatrix* matrix) {
+    displayList->setStaticMatrix(matrix);
+}
+
+static void android_view_GLES20DisplayList_setAnimationMatrix(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, SkMatrix* matrix) {
+    displayList->setAnimationMatrix(matrix);
 }
 
 static void android_view_GLES20DisplayList_setClipChildren(JNIEnv* env,
@@ -175,33 +180,32 @@
 
 static JNINativeMethod gMethods[] = {
 #ifdef USE_OPENGL_RENDERER
-    { "nSetCaching",             "(IZ)V",       (void*) android_view_GLES20DisplayList_setCaching },
-    { "nSetApplicationScale",    "(IF)V",
-            (void*) android_view_GLES20DisplayList_setApplicationScale },
-    { "nSetClipChildren",        "(IZ)V",      (void*) android_view_GLES20DisplayList_setClipChildren },
-    { "nSetAlpha",               "(IF)V",      (void*) android_view_GLES20DisplayList_setAlpha },
-    { "nSetTranslationX",        "(IF)V",      (void*) android_view_GLES20DisplayList_setTranslationX },
-    { "nSetTranslationY",        "(IF)V",      (void*) android_view_GLES20DisplayList_setTranslationY },
-    { "nSetRotation",            "(IF)V",      (void*) android_view_GLES20DisplayList_setRotation },
-    { "nSetRotationX",           "(IF)V",      (void*) android_view_GLES20DisplayList_setRotationX },
-    { "nSetRotationY",           "(IF)V",      (void*) android_view_GLES20DisplayList_setRotationY },
-    { "nSetScaleX",              "(IF)V",      (void*) android_view_GLES20DisplayList_setScaleX },
-    { "nSetScaleY",              "(IF)V",      (void*) android_view_GLES20DisplayList_setScaleY },
-    { "nSetTransformationInfo",  "(IFFFFFFFF)V",
+    { "nSetCaching",           "(IZ)V",  (void*) android_view_GLES20DisplayList_setCaching },
+    { "nSetStaticMatrix",      "(II)V",  (void*) android_view_GLES20DisplayList_setStaticMatrix },
+    { "nSetAnimationMatrix",   "(II)V",  (void*) android_view_GLES20DisplayList_setAnimationMatrix },
+    { "nSetClipChildren",      "(IZ)V",  (void*) android_view_GLES20DisplayList_setClipChildren },
+    { "nSetAlpha",             "(IF)V",  (void*) android_view_GLES20DisplayList_setAlpha },
+    { "nSetTranslationX",      "(IF)V",  (void*) android_view_GLES20DisplayList_setTranslationX },
+    { "nSetTranslationY",      "(IF)V",  (void*) android_view_GLES20DisplayList_setTranslationY },
+    { "nSetRotation",          "(IF)V",  (void*) android_view_GLES20DisplayList_setRotation },
+    { "nSetRotationX",         "(IF)V",  (void*) android_view_GLES20DisplayList_setRotationX },
+    { "nSetRotationY",         "(IF)V",  (void*) android_view_GLES20DisplayList_setRotationY },
+    { "nSetScaleX",            "(IF)V",  (void*) android_view_GLES20DisplayList_setScaleX },
+    { "nSetScaleY",            "(IF)V",  (void*) android_view_GLES20DisplayList_setScaleY },
+    { "nSetTransformationInfo","(IFFFFFFFF)V",
             (void*) android_view_GLES20DisplayList_setTransformationInfo },
-    { "nSetPivotX",              "(IF)V",      (void*) android_view_GLES20DisplayList_setPivotX },
-    { "nSetPivotY",              "(IF)V",      (void*) android_view_GLES20DisplayList_setPivotY },
-    { "nSetCameraDistance",      "(IF)V",
-            (void*) android_view_GLES20DisplayList_setCameraDistance },
-    { "nSetLeft",                "(II)V",      (void*) android_view_GLES20DisplayList_setLeft },
-    { "nSetTop",                 "(II)V",      (void*) android_view_GLES20DisplayList_setTop },
-    { "nSetRight",               "(II)V",      (void*) android_view_GLES20DisplayList_setRight },
-    { "nSetBottom",              "(II)V",      (void*) android_view_GLES20DisplayList_setBottom },
-    { "nSetLeftTop",             "(III)V",     (void*) android_view_GLES20DisplayList_setLeftTop },
-    { "nSetLeftTopRightBottom",  "(IIIII)V",
+    { "nSetPivotX",            "(IF)V",  (void*) android_view_GLES20DisplayList_setPivotX },
+    { "nSetPivotY",            "(IF)V",  (void*) android_view_GLES20DisplayList_setPivotY },
+    { "nSetCameraDistance",    "(IF)V",  (void*) android_view_GLES20DisplayList_setCameraDistance },
+    { "nSetLeft",              "(II)V",  (void*) android_view_GLES20DisplayList_setLeft },
+    { "nSetTop",               "(II)V",  (void*) android_view_GLES20DisplayList_setTop },
+    { "nSetRight",             "(II)V",  (void*) android_view_GLES20DisplayList_setRight },
+    { "nSetBottom",            "(II)V",  (void*) android_view_GLES20DisplayList_setBottom },
+    { "nSetLeftTop",           "(III)V", (void*) android_view_GLES20DisplayList_setLeftTop },
+    { "nSetLeftTopRightBottom","(IIIII)V",
             (void*) android_view_GLES20DisplayList_setLeftTopRightBottom },
-    { "nOffsetLeftRight",        "(II)V",      (void*) android_view_GLES20DisplayList_offsetLeftRight },
-    { "nOffsetTopBottom",        "(II)V",      (void*) android_view_GLES20DisplayList_offsetTopBottom },
+    { "nOffsetLeftRight",      "(II)V",  (void*) android_view_GLES20DisplayList_offsetLeftRight },
+    { "nOffsetTopBottom",      "(II)V",  (void*) android_view_GLES20DisplayList_offsetTopBottom },
 
 #endif
 };
diff --git a/core/jni/android_view_HardwareRenderer.cpp b/core/jni/android_view_HardwareRenderer.cpp
index 082e726..fa83170 100644
--- a/core/jni/android_view_HardwareRenderer.cpp
+++ b/core/jni/android_view_HardwareRenderer.cpp
@@ -20,8 +20,9 @@
 #include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 
+#include <EGL/egl_cache.h>
+
 #ifdef USE_OPENGL_RENDERER
-    #include <EGL/egl_cache.h>
     EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
 #endif
 
diff --git a/docs/html/resources/dashboard/opengl.jd b/docs/html/resources/dashboard/opengl.jd
index b1c3234..4c55522 100644
--- a/docs/html/resources/dashboard/opengl.jd
+++ b/docs/html/resources/dashboard/opengl.jd
@@ -57,7 +57,7 @@
 <div class="dashboard-panel">
 
 <img alt="" width="400" height="250"
-src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=GL%201.1%20only|GL%202.0%20%26%201.1&chd=t%3A10.8,89.2" />
+src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=GL%201.1%20only|GL%202.0%20%26%201.1&chd=t%3A11.9,88.1" />
 
 <table>
 <tr>
@@ -66,14 +66,14 @@
 </tr>
 <tr>
 <td>1.1 only</th>
-<td>10.8%</td>
+<td>11.9%</td>
 </tr>
 <tr>
 <td>2.0 &amp; 1.1</th>
-<td>89.2%</td>
+<td>88.1%</td>
 </tr>
 </table>
 
-<p><em>Data collected during a 7-day period ending on March 4, 2012</em></p>
+<p><em>Data collected during a 7-day period ending on April 2, 2012</em></p>
 </div>
 
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index 65a5575..2cbbe99 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -52,7 +52,7 @@
 <div class="dashboard-panel">
 
 <img alt="" height="250" width="470"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.4,0.8,6.6,25.2,0.5,61.4,0.1,1.1,2.1,0.4,1.2&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0|Android%203.1|Android%203.2|Android%204.0|Android%204.0.3&chco=c4df9b,6fad0c" />
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.3,0.7,6.0,23.1,0.5,63.2,0.1,1.0,2.2,0.5,2.4&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0|Android%203.1|Android%203.2|Android%204.0|Android%204.0.3&chco=c4df9b,6fad0c" />
 
 <table>
 <tr>
@@ -61,25 +61,25 @@
   <th>API Level</th>
   <th>Distribution</th>
 </tr>
-<tr><td><a href="{@docRoot}sdk/android-1.5.html">Android 1.5</a></td><td>Cupcake</td>  <td>3</td><td>0.4%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-1.6.html">Android 1.6</a></td><td>Donut</td>    <td>4</td><td>0.8%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-2.1.html">Android 2.1</a></td><td>Eclair</td>   <td>7</td><td>6.6%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-2.2.html">Android 2.2</a></td><td>Froyo</td>    <td>8</td><td>25.3%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-1.5.html">Android 1.5</a></td><td>Cupcake</td>  <td>3</td><td>0.3%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-1.6.html">Android 1.6</a></td><td>Donut</td>    <td>4</td><td>0.7%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-2.1.html">Android 2.1</a></td><td>Eclair</td>   <td>7</td><td>6.0%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-2.2.html">Android 2.2</a></td><td>Froyo</td>    <td>8</td><td>23.1%</td></tr>
 <tr><td><a href="{@docRoot}sdk/android-2.3.html">Android 2.3 -<br/>
                              Android 2.3.2</a></td><td rowspan="2">Gingerbread</td>    <td>9</td><td>0.5%</td></tr>
 <tr><td><a href="{@docRoot}sdk/android-2.3.3.html">Android 2.3.3 -<br/>
-      Android 2.3.7</a></td><!-- Gingerbread -->                                       <td>10</td><td>61.5%</td></tr>
+      Android 2.3.7</a></td><!-- Gingerbread -->                                       <td>10</td><td>63.2%</td></tr>
 <tr><td><a href="{@docRoot}sdk/android-3.0.html">Android 3.0</a></td>
                                                    <td rowspan="3">Honeycomb</td>      <td>11</td><td>0.1%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-3.1.html">Android 3.1</a></td><!-- Honeycomb --><td>12</td><td>1.1%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-3.2.html">Android 3.2</a></td><!-- Honeycomb --><td>13</td><td>2.1%</td></tr> 
+<tr><td><a href="{@docRoot}sdk/android-3.1.html">Android 3.1</a></td><!-- Honeycomb --><td>12</td><td>1.0%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-3.2.html">Android 3.2</a></td><!-- Honeycomb --><td>13</td><td>2.2%</td></tr> 
 <tr><td><a href="{@docRoot}sdk/android-4.0.html">Android 4.0 -<br/>
                                                Android 4.0.2</a></td>
-                                                <td rowspan="2">Ice Cream Sandwich</td><td>14</td><td>0.4%</td></tr> 
-<tr><td><a href="{@docRoot}sdk/android-4.0.3.html">Android 4.0.3</a></td><!-- ICS     --><td>15</td><td>1.2%</td></tr> 
+                                                <td rowspan="2">Ice Cream Sandwich</td><td>14</td><td>0.5%</td></tr> 
+<tr><td><a href="{@docRoot}sdk/android-4.0.3.html">Android 4.0.3</a></td><!-- ICS     --><td>15</td><td>2.4%</td></tr> 
 </table>
 
-<p><em>Data collected during a 14-day period ending on March 5, 2012</em></p>
+<p><em>Data collected during a 14-day period ending on April 2, 2012</em></p>
 <!--
 <p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p>
 -->
@@ -108,9 +108,9 @@
 <div class="dashboard-panel">
 
 <img alt="" height="250" width="660" style="padding:5px;background:#fff"
-src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C09/01%7C09/15%7C10/01%7C10/15%7C11/01%7C11/15%7C12/01%7C12/15%7C01/01%7C01/15%7C02/01%7C02/15%7C03/01%7C1%3A%7C2011%7C%7C%7C%7C%7C%7C%7C%7C2012%7C%7C%7C%7C2012%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:97.9,97.9,97.7,97.6,97.5,99.4,99.4,99.2,98.9,98.8,99.2,98.9,98.9|96.9,96.9,96.6,96.6,96.5,98.6,98.6,98.5,98.3,98.2,98.6,98.4,98.4|95.1,95.2,95.1,95.4,95.2,97.2,97.3,97.3,97.2,97.2,97.6,97.5,97.6|81.8,82.7,83.3,84.4,84.6,87.0,87.7,88.1,88.7,89.2,89.9,90.3,90.8|30.6,34.1,37.8,40.8,43.5,48.4,52.4,55.2,58.2,60.1,62.0,63.7,65.2|0.0,0.0,0.0,0.0,0.0,2.0,2.3,2.6,3.5,3.6,4.0,4.1,4.3|0.0,0.0,0.0,0.0,0.0,1.0,1.2,1.3,2.0,2.2,2.6,3.0,3.2|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.3,0.4,0.7,0.8,1.1&chm=b,c3df9b,0,1,0|b,b8dc82,1,2,0|tAndroid%202.1,608920,2,0,15,,t::-5|b,addb67,2,3,0|tAndroid%202.2,517617,3,0,15,,t::-5|b,a3db4b,3,4,0|tAndroid%202.3.3,426210,4,0,15,,t::-5|b,98dc2e,4,5,0|b,8cd41b,5,6,0|b,7ec113,6,7,0|B,6fad0c,7,8,0&chg=7,25&chdl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3.3|Android%203.1|Android%203.2|Android%204.0.3&chco=add274,a2d15a,97d13e,8bcb28,7dba1e,6ea715,5f920e,507d08" />
+src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C10/01%7C10/15%7C11/01%7C11/15%7C12/01%7C12/15%7C01/01%7C01/15%7C02/01%7C02/15%7C03/01%7C03/15%7C04/01%7C1%3A%7C2011%7C%7C%7C%7C%7C%7C2012%7C%7C%7C%7C%7C%7C2012%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:97.7,97.6,97.5,99.4,99.4,99.2,98.9,98.8,99.2,98.9,98.9,99.0,98.8|96.6,96.6,96.5,98.6,98.6,98.5,98.3,98.2,98.6,98.4,98.4,98.6,98.5|95.1,95.4,95.2,97.2,97.3,97.3,97.2,97.2,97.6,97.5,97.6,97.8,97.8|83.3,84.4,84.6,87.0,87.7,88.1,88.7,89.2,89.9,90.3,90.8,91.4,91.8|37.8,40.8,43.5,48.4,52.4,55.2,58.2,60.1,62.0,63.7,65.2,66.8,68.6|0.0,0.0,0.0,2.0,2.3,2.6,3.5,3.6,4.0,4.1,4.3,4.6,5.5|0.0,0.0,0.0,1.0,1.2,1.3,2.0,2.2,2.6,3.0,3.2,3.5,4.5|0.0,0.0,0.0,0.0,0.0,0.0,0.3,0.4,0.7,0.8,1.1,1.3,2.3&chm=b,c3df9b,0,1,0|b,b8dc82,1,2,0|tAndroid%202.1,608920,2,0,15,,t::-5|b,addb67,2,3,0|tAndroid%202.2,517617,3,0,15,,t::-5|b,a3db4b,3,4,0|tAndroid%202.3.3,426210,4,0,15,,t::-5|b,98dc2e,4,5,0|b,8cd41b,5,6,0|b,7ec113,6,7,0|B,6fad0c,7,8,0&chg=7,25&chdl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3.3|Android%203.1|Android%203.2|Android%204.0.3&chco=add274,a2d15a,97d13e,8bcb28,7dba1e,6ea715,5f920e,507d08" />
 
-<p><em>Last historical dataset collected during a 14-day period ending on March 5, 2012</em></p>
+<p><em>Last historical dataset collected during a 14-day period ending on April 2, 2012</em></p>
 
 
 </div><!-- end dashboard-panel -->
diff --git a/docs/html/resources/dashboard/screens.jd b/docs/html/resources/dashboard/screens.jd
index e9c738e..e5c79a1 100644
--- a/docs/html/resources/dashboard/screens.jd
+++ b/docs/html/resources/dashboard/screens.jd
@@ -60,7 +60,7 @@
 <div class="dashboard-panel">
 
 <img alt="" width="400" height="250"
-src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=Xlarge%20/%20mdpi|Large%20/%20ldpi|Large%20/%20mdpi|Normal%20/%20hdpi|Normal%20/%20ldpi|Normal%20/%20mdpi|Normal%20/%20xhdpi|Small%20/%20hdpi|Small%20/%20ldpi&chd=t%3A4.9,0.2,2.8,66.4,0.7,18.5,2.5,2.4,1.7" />
+src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=Xlarge%20/%20mdpi|Large%20/%20ldpi|Large%20/%20mdpi|Normal%20/%20hdpi|Normal%20/%20ldpi|Normal%20/%20mdpi|Normal%20/%20xhdpi|Small%20/%20hdpi|Small%20/%20ldpi&chd=t%3A5.8,0.2,2.3,64.6,0.7,19.6,2.4,2.5,1.9" />
 
 <table>
 <tr>
@@ -71,31 +71,31 @@
 <th scope="col">xhdpi</th>
 </tr>
 <tr><th scope="row">small</th> 
-<td>1.7%</td>     <!-- small/ldpi -->
+<td>1.9%</td>     <!-- small/ldpi -->
 <td></td>     <!-- small/mdpi -->
-<td>2.4%</td> <!-- small/hdpi -->
+<td>2.5%</td> <!-- small/hdpi -->
 <td></td>     <!-- small/xhdpi -->
 </tr> 
 <tr><th scope="row">normal</th> 
 <td>0.7%</td>  <!-- normal/ldpi -->
-<td>18.5%</td> <!-- normal/mdpi -->
-<td>66.3%</td> <!-- normal/hdpi -->
-<td>2.5%</td>      <!-- normal/xhdpi -->
+<td>19.6%</td> <!-- normal/mdpi -->
+<td>64.6%</td> <!-- normal/hdpi -->
+<td>2.4%</td>      <!-- normal/xhdpi -->
 </tr> 
 <tr><th scope="row">large</th> 
 <td>0.2%</td>     <!-- large/ldpi -->
-<td>2.8%</td> <!-- large/mdpi -->
+<td>2.3%</td> <!-- large/mdpi -->
 <td></td>     <!-- large/hdpi -->
 <td></td>     <!-- large/xhdpi -->
 </tr> 
 <tr><th scope="row">xlarge</th> 
 <td></td>     <!-- xlarge/ldpi -->
-<td>4.9%</td> <!-- xlarge/mdpi -->
+<td>5.8%</td> <!-- xlarge/mdpi -->
 <td></td>     <!-- xlarge/hdpi -->
 <td></td>     <!-- xlarge/xhdpi -->
 </tr> 
 </table>
 
-<p><em>Data collected during a 7-day period ending on March 4, 2012</em></p>
+<p><em>Data collected during a 7-day period ending on April 2, 2012</em></p>
 </div>
 
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 6b59b10..18a0a0c 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -365,7 +365,7 @@
      * @hide
      *
      */
-    public void ioSendOutput() {
+    public void ioSend() {
         if ((mUsage & USAGE_IO_OUTPUT) == 0) {
             throw new RSIllegalArgumentException(
                 "Can only send buffer if IO_OUTPUT usage specified.");
@@ -375,12 +375,20 @@
     }
 
     /**
+     * Delete once code is updated.
+     * @hide
+     */
+    public void ioSendOutput() {
+        ioSend();
+    }
+
+    /**
      * Receive the latest input into the Allocation.
      *
      * @hide
      *
      */
-    public void ioGetInput() {
+    public void ioReceive() {
         if ((mUsage & USAGE_IO_INPUT) == 0) {
             throw new RSIllegalArgumentException(
                 "Can only receive if IO_INPUT usage specified.");
diff --git a/include/private/hwui/DrawGlInfo.h b/include/private/hwui/DrawGlInfo.h
index abcf41d..8028bf3 100644
--- a/include/private/hwui/DrawGlInfo.h
+++ b/include/private/hwui/DrawGlInfo.h
@@ -44,20 +44,31 @@
     float dirtyBottom;
 
     /**
+     * Values used as the "what" parameter of the functor.
+     */
+    enum Mode {
+        // Indicates that the functor is called to perform a draw
+        kModeDraw,
+        // Indicates the the functor is called only to perform
+        // processing and that no draw should be attempted
+        kModeProcess
+    };
+
+    /**
      * Values used by OpenGL functors to tell the framework
      * what to do next.
      */
     enum Status {
         // The functor is done
-        kStatusDone,
+        kStatusDone = 0x0,
         // The functor is requesting a redraw (the clip rect
         // used by the redraw is specified by DrawGlInfo.)
         // The rest of the UI might redraw too.
-        kStatusDraw,
+        kStatusDraw = 0x1,
         // The functor needs to be invoked again but will
         // not redraw. Only the functor is invoked again
         // (unless another functor requests a redraw.)
-        kStatusInvoke
+        kStatusInvoke = 0x2
     };
 }; // struct DrawGlInfo
 
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 3a3f8a5..f37bfd2 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -94,7 +94,8 @@
 }
 
 DisplayList::DisplayList(const DisplayListRenderer& recorder) :
-    mTransformMatrix(NULL), mTransformCamera(NULL), mTransformMatrix3D(NULL) {
+    mTransformMatrix(NULL), mTransformCamera(NULL), mTransformMatrix3D(NULL),
+    mStaticMatrix(NULL), mAnimationMatrix(NULL) {
 
     initFromDisplayListRenderer(recorder);
 }
@@ -108,7 +109,6 @@
     mTop = 0;
     mRight = 0;
     mBottom = 0;
-    mApplicationScale = -1;
     mClipChildren = true;
     mAlpha = 1;
     mMultipliedAlpha = 255;
@@ -143,18 +143,16 @@
     sk_free((void*) mReader.base());
 
     if (USE_DISPLAY_LIST_PROPERTIES) {
-        if (mTransformMatrix) {
-            delete mTransformMatrix;
-            mTransformMatrix = NULL;
-        }
-        if (mTransformCamera) {
-            delete mTransformCamera;
-            mTransformCamera = NULL;
-        }
-        if (mTransformMatrix3D) {
-            delete mTransformMatrix3D;
-            mTransformMatrix3D = NULL;
-        }
+        delete mTransformMatrix;
+        delete mTransformCamera;
+        delete mTransformMatrix3D;
+        delete mStaticMatrix;
+        delete mAnimationMatrix;
+        mTransformMatrix = NULL;
+        mTransformCamera = NULL;
+        mTransformMatrix3D = NULL;
+        mStaticMatrix = NULL;
+        mAnimationMatrix = NULL;
     }
 
     Caches& caches = Caches::getInstance();
@@ -667,12 +665,26 @@
 void DisplayList::outputViewProperties(OpenGLRenderer& renderer, char* indent) {
     if (USE_DISPLAY_LIST_PROPERTIES) {
         updateMatrix();
-        if (mApplicationScale >= 0) {
-            ALOGD("%s%s %.2f, %.2f", (char*) indent, "Scale",
-                    mApplicationScale, mApplicationScale);
-        }
         if (mLeft != 0 || mTop != 0) {
-            ALOGD("%s%s %d, %d", indent, "Translate", mLeft, mTop);
+            ALOGD("%s%s %d, %d", indent, "Translate (left, top)", mLeft, mTop);
+        }
+        if (mStaticMatrix) {
+            ALOGD("%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
+                    indent, "ConcatMatrix (static)", mStaticMatrix,
+                    mStaticMatrix->get(0), mStaticMatrix->get(1),
+                    mStaticMatrix->get(2), mStaticMatrix->get(3),
+                    mStaticMatrix->get(4), mStaticMatrix->get(5),
+                    mStaticMatrix->get(6), mStaticMatrix->get(7),
+                    mStaticMatrix->get(8));
+        }
+        if (mAnimationMatrix) {
+            ALOGD("%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
+                    indent, "ConcatMatrix (animation)", mAnimationMatrix,
+                    mAnimationMatrix->get(0), mAnimationMatrix->get(1),
+                    mAnimationMatrix->get(2), mAnimationMatrix->get(3),
+                    mAnimationMatrix->get(4), mAnimationMatrix->get(5),
+                    mAnimationMatrix->get(6), mAnimationMatrix->get(7),
+                    mAnimationMatrix->get(8));
         }
         if (mMatrixFlags != 0) {
             if (mMatrixFlags == TRANSLATION) {
@@ -719,13 +731,29 @@
 #endif
         updateMatrix();
         if (mLeft != 0 || mTop != 0) {
-            DISPLAY_LIST_LOGD("%s%s %d, %d", indent, "Translate", mLeft, mTop);
+            DISPLAY_LIST_LOGD("%s%s %d, %d", indent, "Translate (left, top)", mLeft, mTop);
             renderer.translate(mLeft, mTop);
         }
-        if (mApplicationScale >= 0) {
-            DISPLAY_LIST_LOGD("%s%s %.2f, %.2f", (char*) indent, "Scale",
-                    mApplicationScale, mApplicationScale);
-            renderer.scale(mApplicationScale, mApplicationScale);
+        if (mStaticMatrix) {
+            DISPLAY_LIST_LOGD(
+                    "%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
+                    indent, "ConcatMatrix (static)", mStaticMatrix,
+                    mStaticMatrix->get(0), mStaticMatrix->get(1),
+                    mStaticMatrix->get(2), mStaticMatrix->get(3),
+                    mStaticMatrix->get(4), mStaticMatrix->get(5),
+                    mStaticMatrix->get(6), mStaticMatrix->get(7),
+                    mStaticMatrix->get(8));
+            renderer.concatMatrix(mStaticMatrix);
+        } else if (mAnimationMatrix) {
+            DISPLAY_LIST_LOGD(
+                    "%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
+                    indent, "ConcatMatrix (animation)", mAnimationMatrix,
+                    mAnimationMatrix->get(0), mAnimationMatrix->get(1),
+                    mAnimationMatrix->get(2), mAnimationMatrix->get(3),
+                    mAnimationMatrix->get(4), mAnimationMatrix->get(5),
+                    mAnimationMatrix->get(6), mAnimationMatrix->get(7),
+                    mAnimationMatrix->get(8));
+            renderer.concatMatrix(mAnimationMatrix);
         }
         if (mMatrixFlags != 0) {
             if (mMatrixFlags == TRANSLATION) {
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index fff1d7c..38b0a6d 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -51,7 +51,7 @@
 
 // Set to 1 to enable native processing of View properties. 0 by default. Eventually this
 // will go away and we will always use this approach for accelerated apps.
-#define USE_DISPLAY_LIST_PROPERTIES 0
+#define USE_DISPLAY_LIST_PROPERTIES 1
 
 #define TRANSLATION 0x0001
 #define ROTATION    0x0002
@@ -156,14 +156,24 @@
         }
     }
 
-    void setApplicationScale(float scale) {
-        mApplicationScale = scale;
-    }
-
     void setClipChildren(bool clipChildren) {
         mClipChildren = clipChildren;
     }
 
+    void setStaticMatrix(SkMatrix* matrix) {
+        delete mStaticMatrix;
+        mStaticMatrix = new SkMatrix(*matrix);
+    }
+
+    void setAnimationMatrix(SkMatrix* matrix) {
+        delete mAnimationMatrix;
+        if (matrix) {
+            mAnimationMatrix = new SkMatrix(*matrix);
+        } else {
+            mAnimationMatrix = NULL;
+        }
+    }
+
     void setAlpha(float alpha) {
         if (alpha != mAlpha) {
             mAlpha = alpha;
@@ -483,7 +493,6 @@
     String8 mName;
 
     // View properties
-    float mApplicationScale;
     bool mClipChildren;
     float mAlpha;
     int mMultipliedAlpha;
@@ -502,6 +511,8 @@
     SkMatrix* mTransformMatrix;
     Sk3DView* mTransformCamera;
     SkMatrix* mTransformMatrix3D;
+    SkMatrix* mStaticMatrix;
+    SkMatrix* mAnimationMatrix;
     bool mCaching;
 };
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index eb4b83b..39be5ed 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -166,6 +166,7 @@
 
 void OpenGLRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) {
     mCaches.clearGarbage();
+    mFunctors.clear();
 
     mSnapshot = new Snapshot(mFirstSnapshot,
             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
@@ -236,7 +237,39 @@
     glBlendEquation(GL_FUNC_ADD);
 }
 
-status_t OpenGLRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) {
+status_t OpenGLRenderer::invokeFunctors(Rect& dirty) {
+    status_t result = DrawGlInfo::kStatusDone;
+
+    Vector<Functor*> functors(mFunctors);
+    mFunctors.clear();
+
+    DrawGlInfo info;
+    info.clipLeft = 0;
+    info.clipTop = 0;
+    info.clipRight = 0;
+    info.clipBottom = 0;
+    info.isLayer = false;
+    memset(info.transform, 0, sizeof(float) * 16);
+
+    size_t count = functors.size();
+    for (size_t i = 0; i < count; i++) {
+        Functor* f = functors.itemAt(i);
+        result |= (*f)(DrawGlInfo::kModeProcess, &info);
+
+        if (result != DrawGlInfo::kStatusDone) {
+            Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
+            dirty.unionWith(localDirty);
+
+            if (result == DrawGlInfo::kStatusInvoke) {
+                mFunctors.push(f);
+            }
+        }
+    }
+
+    return result;
+}
+
+status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
     interrupt();
     if (mDirtyClip) {
         setScissorFromClip();
@@ -261,11 +294,15 @@
     info.isLayer = hasLayer();
     getSnapshot()->transform->copyTo(&info.transform[0]);
 
-    status_t result = (*functor)(0, &info);
+    status_t result = (*functor)(DrawGlInfo::kModeDraw, &info);
 
-    if (result != 0) {
+    if (result != DrawGlInfo::kStatusDone) {
         Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
         dirty.unionWith(localDirty);
+
+        if (result == DrawGlInfo::kStatusInvoke) {
+            mFunctors.push(functor);
+        }
     }
 
     resume();
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 3ba6202..b651904 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -72,7 +72,8 @@
     virtual void interrupt();
     virtual void resume();
 
-    virtual status_t callDrawGLFunction(Functor *functor, Rect& dirty);
+    ANDROID_API status_t invokeFunctors(Rect& dirty);
+    virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty);
 
     ANDROID_API int getSaveCount() const;
     virtual int save(int flags);
@@ -602,8 +603,10 @@
     // Various caches
     Caches& mCaches;
 
-    // List of rectagnles to clear after saveLayer() is invoked
+    // List of rectangles to clear after saveLayer() is invoked
     Vector<Rect*> mLayers;
+    // List of functors to invoke after a frame is drawn
+    Vector<Functor*> mFunctors;
 
     // Indentity matrix
     const mat4 mIdentity;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index bbaebd9..ab4012f 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3587,11 +3587,9 @@
                 // If uid is specified and the uid and process name match
                 // Or, the uid is not specified and the process name matches
                 } else if (((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
-                            && (app.processName.equals(packageName)
-                                || app.processName.startsWith(procNamePrefix)))
-                           || (uid < 0
-                               && (app.processName.equals(packageName)
-                                       || app.processName.startsWith(procNamePrefix)))) {
+                            || ((app.processName.equals(packageName)
+                                 || app.processName.startsWith(procNamePrefix))
+                                && uid < 0))) {
                     if (app.setAdj >= minOomAdj) {
                         if (!doit) {
                             return true;
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index d1f1b44..3069b74 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -376,7 +376,8 @@
         int numDrawn = 0;
         boolean nowGone = true;
 
-        if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Update reported visibility: " + this);
+        if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG,
+                "Update reported visibility: " + this);
         final int N = allAppWindows.size();
         for (int i=0; i<N; i++) {
             WindowState win = allAppWindows.get(i);
@@ -393,8 +394,7 @@
                 if (!win.isDrawnLw()) {
                     Slog.v(WindowManagerService.TAG, "Not displayed: s=" + win.mWinAnimator.mSurface
                             + " pv=" + win.mPolicyVisibility
-                            + " dp=" + win.mWinAnimator.mDrawPending
-                            + " cdp=" + win.mWinAnimator.mCommitDrawPending
+                            + " mDrawState=" + win.mWinAnimator.mDrawState
                             + " ah=" + win.mAttachedHidden
                             + " th="
                             + (win.mAppToken != null
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 26f4d0d..5a104b2 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -299,8 +299,7 @@
                         if (!w.isDrawnLw()) {
                             Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurface
                                     + " pv=" + w.mPolicyVisibility
-                                    + " dp=" + winAnimator.mDrawPending
-                                    + " cdp=" + winAnimator.mCommitDrawPending
+                                    + " mDrawState=" + winAnimator.mDrawState
                                     + " ah=" + w.mAttachedHidden
                                     + " th=" + atoken.hiddenRequested
                                     + " a=" + winAnimator.mAnimating);
@@ -323,7 +322,7 @@
                         atoken.startingDisplayed = true;
                     }
                 }
-            } else if (w.mReadyToShow) {
+            } else if (winAnimator.mDrawState == WindowStateAnimator.READY_TO_SHOW) {
                 if (winAnimator.performShowLocked()) {
                     mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
                     if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index f84838b..afbc348 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -1589,8 +1589,7 @@
                 }
             }
             if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": readyfordisplay="
-                    + w.isReadyForDisplay() + " drawpending=" + w.mWinAnimator.mDrawPending
-                    + " commitdrawpending=" + w.mWinAnimator.mCommitDrawPending);
+                    + w.isReadyForDisplay() + " mDrawState=" + w.mWinAnimator.mDrawState);
             if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 && w.isReadyForDisplay()
                     && (mWallpaperTarget == w || w.isDrawnLw())) {
                 if (DEBUG_WALLPAPER) Slog.v(TAG,
@@ -1972,6 +1971,11 @@
         }
     }
 
+    // TODO(cmautner):  Move to WindowAnimator.
+    void setWallpaperOffset(final WindowStateAnimator winAnimator, final int left, final int top) {
+        mH.sendMessage(mH.obtainMessage(H.SET_WALLPAPER_OFFSET, left, top, winAnimator));
+    }
+
     void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) {
         final int dw = mAppDisplayWidth;
         final int dh = mAppDisplayHeight;
@@ -2010,10 +2014,8 @@
                             if (SHOW_TRANSACTIONS) logSurface(wallpaper,
                                     "POS " + wallpaper.mShownFrame.left
                                     + ", " + wallpaper.mShownFrame.top, null);
-                            winAnimator.mSurfaceX = wallpaper.mShownFrame.left;
-                            winAnimator.mSurfaceY = wallpaper.mShownFrame.top;
-                            winAnimator.mSurface.setPosition(wallpaper.mShownFrame.left,
-                                    wallpaper.mShownFrame.top);
+                            setWallpaperOffset(winAnimator, (int) wallpaper.mShownFrame.left,
+                                (int) wallpaper.mShownFrame.top);
                         } catch (RuntimeException e) {
                             Slog.w(TAG, "Error positioning surface of " + wallpaper
                                     + " pos=(" + wallpaper.mShownFrame.left
@@ -2314,7 +2316,7 @@
         // to hold off on removing the window until the animation is done.
         // If the display is frozen, just remove immediately, since the
         // animation wouldn't be seen.
-        if (win.mWinAnimator.mSurface != null && okToDisplay()) {
+        if (win.mHasSurface && okToDisplay()) {
             // If we are not currently running the exit animation, we
             // need to see about starting one.
             wasVisible = win.isWinVisibleLw();
@@ -2458,8 +2460,7 @@
     }
 
     static void logSurface(WindowState w, String msg, RuntimeException where) {
-        String str = "  SURFACE " + Integer.toHexString(w.hashCode())
-                + ": " + msg + " / " + w.mAttrs.getTitle();
+        String str = "  SURFACE " + msg + ": " + w;
         if (where != null) {
             Slog.i(TAG, str, where);
         } else {
@@ -2475,26 +2476,20 @@
             Slog.i(TAG, str);
         }
     }
-    
+
+    // TODO(cmautner): Move to WindowStateAnimator.
+    void setTransparentRegionHint(final WindowStateAnimator winAnimator, final Region region) {
+        mH.sendMessage(mH.obtainMessage(H.SET_TRANSPARENT_REGION,
+                new Pair<WindowStateAnimator, Region>(winAnimator, region)));
+    }
+
     void setTransparentRegionWindow(Session session, IWindow client, Region region) {
         long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mWindowMap) {
                 WindowState w = windowForClientLocked(session, client, false);
-                WindowStateAnimator winAnimator = w.mWinAnimator;
-                if ((w != null) && (winAnimator.mSurface != null)) {
-                    if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
-                            ">>> OPEN TRANSACTION setTransparentRegion");
-                    Surface.openTransaction();
-                    try {
-                        if (SHOW_TRANSACTIONS) logSurface(w,
-                                "transparentRegionHint=" + region, null);
-                        winAnimator.mSurface.setTransparentRegionHint(region);
-                    } finally {
-                        Surface.closeTransaction();
-                        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
-                                "<<< CLOSE TRANSACTION setTransparentRegion");
-                    }
+                if ((w != null) && w.mHasSurface) {
+                    setTransparentRegionHint(w.mWinAnimator, region);
                 }
             }
         } finally {
@@ -2617,11 +2612,12 @@
         long origId = Binder.clearCallingIdentity();
 
         synchronized(mWindowMap) {
+            // TODO(cmautner): synchronize on mAnimator or win.mWinAnimator.
             WindowState win = windowForClientLocked(session, client, false);
-            WindowStateAnimator winAnimator = win.mWinAnimator;
             if (win == null) {
                 return 0;
             }
+            WindowStateAnimator winAnimator = win.mWinAnimator;
             if (win.mRequestedWidth != requestedWidth
                     || win.mRequestedHeight != requestedHeight) {
                 win.mLayoutNeeded = true;
@@ -2702,6 +2698,7 @@
                 displayed = !win.isVisibleLw();
                 if (win.mExiting) {
                     winAnimator.cancelExitAnimationForNextAnimationLocked();
+                    win.mExiting = false;
                 }
                 if (win.mDestroying) {
                     win.mDestroying = false;
@@ -2740,7 +2737,7 @@
                     surfaceChanged = true;
                 }
                 try {
-                    if (winAnimator.mSurface == null) {
+                    if (!win.mHasSurface) {
                         surfaceChanged = true;
                     }
                     Surface surface = winAnimator.createSurfaceLocked();
@@ -3416,15 +3413,13 @@
     }
 
     public int getOrientationFromAppTokensLocked() {
-        int pos = mAppTokens.size() - 1;
         int curGroup = 0;
         int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
         boolean findingBehind = false;
         boolean haveGroup = false;
         boolean lastFullscreen = false;
-        while (pos >= 0) {
+        for (int pos = mAppTokens.size() - 1; pos >= 0; pos--) {
             AppWindowToken wtoken = mAppTokens.get(pos);
-            pos--;
 
             if (DEBUG_APP_ORIENTATION) Slog.v(TAG, "Checking app orientation: " + wtoken);
 
@@ -4138,7 +4133,7 @@
                 WindowState w = wtoken.allAppWindows.get(i);
                 if (w.mAppFreezing) {
                     w.mAppFreezing = false;
-                    if (w.mWinAnimator.mSurface != null && !w.mOrientationChanging) {
+                    if (w.mHasSurface && !w.mOrientationChanging) {
                         if (DEBUG_ORIENTATION) Slog.v(TAG, "set mOrientationChanging of " + w);
                         w.mOrientationChanging = true;
                     }
@@ -4726,7 +4721,7 @@
         synchronized(mWindowMap) {
             for (int i=mWindows.size()-1; i>=0; i--) {
                 WindowState w = mWindows.get(i);
-                if (w.mWinAnimator.mSurface != null) {
+                if (w.mHasSurface) {
                     try {
                         w.mClient.closeSystemDialogs(reason);
                     } catch (RemoteException e) {
@@ -5198,7 +5193,7 @@
             boolean including = false;
             for (int i=mWindows.size()-1; i>=0; i--) {
                 WindowState ws = mWindows.get(i);
-                if (ws.mWinAnimator.mSurface == null) {
+                if (!ws.mHasSurface) {
                     continue;
                 }
                 if (ws.mLayer >= aboveAppLayer) {
@@ -5512,7 +5507,7 @@
 
         for (int i=mWindows.size()-1; i>=0; i--) {
             WindowState w = mWindows.get(i);
-            if (w.mWinAnimator.mSurface != null) {
+            if (w.mHasSurface) {
                 if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w);
                 w.mOrientationChanging = true;
             }
@@ -6659,6 +6654,10 @@
         public static final int WAITING_FOR_DRAWN_TIMEOUT = 24;
         public static final int BULK_UPDATE_PARAMETERS = 25;
 
+        public static final int ANIMATOR_WHAT_OFFSET = 100000;
+        public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
+        public static final int SET_WALLPAPER_OFFSET = ANIMATOR_WHAT_OFFSET + 2;
+
         private Session mLastReportedHold;
 
         public H() {
@@ -7082,6 +7081,28 @@
 
                         requestTraversalLocked();
                     }
+                    break;
+                }
+
+                // Animation messages. Move to Window{State}Animator
+                case SET_TRANSPARENT_REGION: {
+                    // TODO(cmautner): Remove sync.
+                    synchronized (mWindowMap) {
+                        Pair<WindowStateAnimator, Region> pair =
+                                (Pair<WindowStateAnimator, Region>) msg.obj;
+                        final WindowStateAnimator winAnimator = pair.first;
+                        winAnimator.setTransparentRegionHint(pair.second);
+                    }
+                    break;
+                }
+
+                case SET_WALLPAPER_OFFSET: {
+                    // TODO(cmautner): Remove sync.
+                    synchronized (mWindowMap) {
+                        final WindowStateAnimator winAnimator = (WindowStateAnimator) msg.obj;
+                        winAnimator.setWallpaperOffset(msg.arg1, msg.arg2);
+                    }
+                    break;
                 }
             }
         }
@@ -8027,7 +8048,7 @@
             mAnimator.mForceHiding = false;
             for (int i=mWindows.size()-1; i>=0; i--) {
                 WindowState w = mWindows.get(i);
-                if (w.mWinAnimator.mSurface != null) {
+                if (w.mHasSurface) {
                     final WindowManager.LayoutParams attrs = w.mAttrs;
                     if (mPolicy.doesForceHide(w, attrs) && w.isVisibleLw()) {
                         if (DEBUG_FOCUS) Slog.i(TAG, "win=" + w + " force hides other windows");
@@ -8089,9 +8110,7 @@
                     if (DEBUG_ORIENTATION) Slog.v(TAG,
                             "Orientation start waiting for draw in "
                             + w + ", surface " + w.mWinAnimator.mSurface);
-                    winAnimator.mDrawPending = true;
-                    winAnimator.mCommitDrawPending = false;
-                    w.mReadyToShow = false;
+                    winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
                     if (w.mAppToken != null) {
                         w.mAppToken.allDrawn = false;
                     }
@@ -8127,7 +8146,7 @@
         final int attrFlags = attrs.flags;
         final boolean canBeSeen = w.isDisplayedLw();
 
-        if (w.mWinAnimator.mSurface != null) {
+        if (w.mHasSurface) {
             if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
                 mInnerFields.mHoldScreen = w.mSession;
             }
@@ -8279,7 +8298,7 @@
                 mPolicy.beginAnimationLw(dw, dh);
                 for (i = mWindows.size() - 1; i >= 0; i--) {
                     WindowState w = mWindows.get(i);
-                    if (w.mWinAnimator.mSurface != null) {
+                    if (w.mHasSurface) {
                         mPolicy.animatingWindowLw(w, w.mAttrs);
                     }
                 }
@@ -8397,7 +8416,7 @@
             updateResizingWindows(w);
 
             // Moved from updateWindowsAndWallpaperLocked().
-            if (winAnimator.mSurface != null) {
+            if (w.mHasSurface) {
                 // Take care of the window being ready to display.
                 if (winAnimator.commitFinishDrawingLocked(currentTime)) {
                     if ((w.mAttrs.flags
@@ -8456,10 +8475,8 @@
             stopFreezingDisplayLocked();
         }
 
-        i = mResizingWindows.size();
-        if (i > 0) {
-            do {
-                i--;
+        if (!mResizingWindows.isEmpty()) {
+            for (i = mResizingWindows.size() - 1; i >= 0; i--) {
                 WindowState win = mResizingWindows.get(i);
                 final WindowStateAnimator winAnimator = win.mWinAnimator; 
                 try {
@@ -8478,19 +8495,21 @@
                                 + Integer.toHexString(diff));
                     }
                     win.mConfiguration = mCurConfiguration;
-                    if (DEBUG_ORIENTATION && winAnimator.mDrawPending) Slog.i(
+                    if (DEBUG_ORIENTATION &&
+                            winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
                             TAG, "Resizing " + win + " WITH DRAW PENDING"); 
                     win.mClient.resized((int)winAnimator.mSurfaceW,
                             (int)winAnimator.mSurfaceH,
                             win.mLastContentInsets, win.mLastVisibleInsets,
-                            winAnimator.mDrawPending, configChanged ? win.mConfiguration : null);
+                            winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING,
+                            configChanged ? win.mConfiguration : null);
                     win.mContentInsetsChanged = false;
                     win.mVisibleInsetsChanged = false;
                     winAnimator.mSurfaceResized = false;
                 } catch (RemoteException e) {
                     win.mOrientationChanging = false;
                 }
-            } while (i > 0);
+            }
             mResizingWindows.clear();
         }
 
@@ -8725,6 +8744,7 @@
                         wsa.mSurface.destroy();
                         wsa.mSurfaceShown = false;
                         wsa.mSurface = null;
+                        ws.mHasSurface = false;
                         mForceRemoves.add(ws);
                         i--;
                         N--;
@@ -8737,6 +8757,7 @@
                         wsa.mSurface.destroy();
                         wsa.mSurfaceShown = false;
                         wsa.mSurface = null;
+                        ws.mHasSurface = false;
                         leakedSurface = true;
                     }
                 }
@@ -8775,6 +8796,7 @@
                     surface.destroy();
                     winAnimator.mSurfaceShown = false;
                     winAnimator.mSurface = null;
+                    winAnimator.mWin.mHasSurface = false;
                 }
 
                 try {
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 7f63429..b74aa61 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -83,7 +83,6 @@
     boolean mPolicyVisibilityAfterAnim = true;
     boolean mAppFreezing;
     boolean mAttachedHidden;    // is our parent window hidden?
-    boolean mLastHidden;        // was this window last hidden?
     boolean mWallpaperVisible;  // for wallpaper, what was last vis report?
 
     /**
@@ -206,15 +205,6 @@
     // when in that case until the layout is done.
     boolean mLayoutNeeded;
 
-    // This is set during the time after the window's drawing has been
-    // committed, and before its surface is actually shown.  It is used
-    // to delay showing the surface until all windows in a token are ready
-    // to be shown.
-    boolean mReadyToShow;
-
-    // Set when the window has been shown in the screen the first time.
-    boolean mHasDrawn;
-
     // Currently running an exit animation?
     boolean mExiting;
 
@@ -246,6 +236,8 @@
 
     final WindowStateAnimator mWinAnimator;
 
+    boolean mHasSurface = false;
+
     WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
            WindowState attachedWindow, int seq, WindowManager.LayoutParams a,
            int viewVisibility) {
@@ -609,7 +601,7 @@
      */
     public boolean isVisibleLw() {
         final AppWindowToken atoken = mAppToken;
-        return mWinAnimator.mSurface != null && mPolicyVisibility && !mAttachedHidden
+        return mHasSurface && mPolicyVisibility && !mAttachedHidden
                 && (atoken == null || !atoken.hiddenRequested)
                 && !mExiting && !mDestroying;
     }
@@ -630,7 +622,7 @@
         final AppWindowToken atoken = mAppToken;
         final boolean animating = atoken != null
                 ? (atoken.animation != null) : false;
-        return mWinAnimator.mSurface != null && !mDestroying && !mExiting
+        return mHasSurface && !mDestroying && !mExiting
                 && (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested)
                 && ((!mAttachedHidden && mViewVisibility == View.VISIBLE
                                 && !mRootToken.hidden)
@@ -644,7 +636,7 @@
      */
     public boolean isWinVisibleLw() {
         final AppWindowToken atoken = mAppToken;
-        return mWinAnimator.mSurface != null && mPolicyVisibility && !mAttachedHidden
+        return mHasSurface && mPolicyVisibility && !mAttachedHidden
                 && (atoken == null || !atoken.hiddenRequested || atoken.animating)
                 && !mExiting && !mDestroying;
     }
@@ -654,7 +646,7 @@
      * the associated app token, not the pending requested hidden state.
      */
     boolean isVisibleNow() {
-        return mWinAnimator.mSurface != null && mPolicyVisibility && !mAttachedHidden
+        return mHasSurface && mPolicyVisibility && !mAttachedHidden
                 && !mRootToken.hidden && !mExiting && !mDestroying;
     }
 
@@ -674,7 +666,7 @@
      */
     boolean isVisibleOrAdding() {
         final AppWindowToken atoken = mAppToken;
-        return ((mWinAnimator.mSurface != null && !mWinAnimator.mReportDestroySurface)
+        return ((mHasSurface && !mWinAnimator.mReportDestroySurface)
                         || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
                 && mPolicyVisibility && !mAttachedHidden
                 && (atoken == null || !atoken.hiddenRequested)
@@ -687,15 +679,15 @@
      * being visible.
      */
     boolean isOnScreen() {
+        if (!mHasSurface || !mPolicyVisibility || mDestroying) {
+            return false;
+        }
         final AppWindowToken atoken = mAppToken;
         if (atoken != null) {
-            return mWinAnimator.mSurface != null && mPolicyVisibility && !mDestroying
-                    && ((!mAttachedHidden && !atoken.hiddenRequested)
+            return ((!mAttachedHidden && !atoken.hiddenRequested)
                             || mWinAnimator.mAnimation != null || atoken.animation != null);
-        } else {
-            return mWinAnimator.mSurface != null && mPolicyVisibility && !mDestroying
-                    && (!mAttachedHidden || mWinAnimator.mAnimation != null);
         }
+        return !mAttachedHidden || mWinAnimator.mAnimation != null;
     }
 
     /**
@@ -707,7 +699,7 @@
                 mService.mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
             return false;
         }
-        return mWinAnimator.mSurface != null && mPolicyVisibility && !mDestroying
+        return mHasSurface && mPolicyVisibility && !mDestroying
                 && ((!mAttachedHidden && mViewVisibility == View.VISIBLE
                                 && !mRootToken.hidden)
                         || mWinAnimator.mAnimation != null
@@ -741,8 +733,9 @@
      * complete UI in to.
      */
     public boolean isDrawnLw() {
-        return mWinAnimator.mSurface != null && !mDestroying
-            && !mWinAnimator.mDrawPending && !mWinAnimator.mCommitDrawPending;
+        return mHasSurface && !mDestroying &&
+                (mWinAnimator.mDrawState == WindowStateAnimator.READY_TO_SHOW
+                || mWinAnimator.mDrawState == WindowStateAnimator.HAS_DRAWN);
     }
 
     /**
@@ -762,7 +755,7 @@
      * sense to call from performLayoutAndPlaceSurfacesLockedInner().)
      */
     boolean shouldAnimateMove() {
-        return mContentChanged && !mExiting && !mLastHidden && mService.okToDisplay()
+        return mContentChanged && !mExiting && !mWinAnimator.mLastHidden && mService.okToDisplay()
                 && (mFrame.top != mLastFrame.top
                         || mFrame.left != mLastFrame.left)
                 && (mAttachedWindow == null || !mAttachedWindow.shouldAnimateMove());
@@ -835,10 +828,12 @@
                 && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0);
     }
 
+    @Override
     public boolean hasDrawnLw() {
-        return mHasDrawn;
+        return mWinAnimator.mDrawState == WindowStateAnimator.HAS_DRAWN;
     }
 
+    @Override
     public boolean showLw(boolean doAnimation) {
         return showLw(doAnimation, true);
     }
@@ -983,7 +978,6 @@
             }
             pw.print(prefix); pw.print("mViewVisibility=0x");
             pw.print(Integer.toHexString(mViewVisibility));
-            pw.print(" mLastHidden="); pw.print(mLastHidden);
             pw.print(" mHaveFrame="); pw.print(mHaveFrame);
             pw.print(" mObscured="); pw.println(mObscured);
             pw.print(prefix); pw.print("mSeq="); pw.print(mSeq);
@@ -1017,8 +1011,8 @@
             }
             pw.print(prefix); pw.print("mConfiguration="); pw.println(mConfiguration);
         }
-        pw.print(prefix); pw.print("mShownFrame=");
-                mShownFrame.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface);
+                pw.print(" mShownFrame="); mShownFrame.printShortString(pw); pw.println();
         if (dumpAll) {
             pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw);
                     pw.print(" last="); mLastFrame.printShortString(pw);
@@ -1046,12 +1040,6 @@
                     pw.println();
         }
         mWinAnimator.dump(pw, prefix, dumpAll);
-        if (dumpAll) {
-            pw.print(prefix); pw.print("mDrawPending="); pw.print(mWinAnimator.mDrawPending);
-                    pw.print(" mCommitDrawPending="); pw.print(mWinAnimator.mCommitDrawPending);
-                    pw.print(" mReadyToShow="); pw.print(mReadyToShow);
-                    pw.print(" mHasDrawn="); pw.println(mHasDrawn);
-        }
         if (mExiting || mRemoveOnExit || mDestroying || mRemoved) {
             pw.print(prefix); pw.print("mExiting="); pw.print(mExiting);
                     pw.print(" mRemoveOnExit="); pw.print(mRemoveOnExit);
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index e99340c..4979a4c 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -9,6 +9,7 @@
 import android.graphics.Matrix;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.os.RemoteException;
 import android.util.Slog;
 import android.view.Surface;
@@ -35,6 +36,7 @@
     static final boolean SHOW_LIGHT_TRANSACTIONS = WindowManagerService.SHOW_LIGHT_TRANSACTIONS;
     static final boolean SHOW_SURFACE_ALLOC = WindowManagerService.SHOW_SURFACE_ALLOC;
     static final boolean localLOGV = WindowManagerService.localLOGV;
+    static final boolean DEBUG_ORIENTATION = WindowManagerService.DEBUG_ORIENTATION;
 
     static final String TAG = "WindowStateAnimator";
 
@@ -98,14 +100,24 @@
     // an enter animation.
     boolean mEnterAnimationPending;
 
-    // This is set after the Surface has been created but before the
-    // window has been drawn.  During this time the surface is hidden.
-    boolean mDrawPending;
+    /** This is set when there is no Surface */
+    static final int NO_SURFACE = 0;
+    /** This is set after the Surface has been created but before the window has been drawn. During
+     * this time the surface is hidden. */
+    static final int DRAW_PENDING = 1;
+    /** This is set after the window has finished drawing for the first time but before its surface
+     * is shown.  The surface will be displayed when the next layout is run. */
+    static final int COMMIT_DRAW_PENDING = 2;
+    /** This is set during the time after the window's drawing has been committed, and before its
+     * surface is actually shown.  It is used to delay showing the surface until all windows in a
+     * token are ready to be shown. */
+    static final int READY_TO_SHOW = 3;
+    /** Set when the window has been shown in the screen the first time. */
+    static final int HAS_DRAWN = 4;
+    int mDrawState;
 
-    // This is set after the window has finished drawing for the first
-    // time but before its surface is shown.  The surface will be
-    // displayed when the next layout is run.
-    boolean mCommitDrawPending;
+    /** Was this window last hidden? */
+    boolean mLastHidden;
 
     public WindowStateAnimator(final WindowManagerService service, final WindowState win,
                                final WindowState attachedWindow) {
@@ -128,7 +140,7 @@
         mAnimation.scaleCurrentDuration(mService.mWindowAnimationScale);
         // Start out animation gone if window is gone, or visible if window is visible.
         mTransformation.clear();
-        mTransformation.setAlpha(mWin.mLastHidden ? 0 : 1);
+        mTransformation.setAlpha(mLastHidden ? 0 : 1);
         mHasLocalTransformation = true;
     }
 
@@ -158,13 +170,11 @@
     }
 
     void cancelExitAnimationForNextAnimationLocked() {
-        if (!mWin.mExiting) return;
         if (mAnimation != null) {
             mAnimation.cancel();
             mAnimation = null;
             destroySurfaceLocked();
         }
-        mWin.mExiting = false;
     }
 
     private boolean stepAnimation(long currentTime) {
@@ -291,7 +301,7 @@
             }
         }
         mTransformation.clear();
-        if (mWin.mHasDrawn
+        if (mDrawState == HAS_DRAWN
                 && mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
                 && mWin.mAppToken != null
                 && mWin.mAppToken.firstWindowDrawn
@@ -347,7 +357,7 @@
             } catch (RuntimeException e) {
                 Slog.w(TAG, "Error hiding surface in " + this, e);
             }
-            mWin.mLastHidden = true;
+            mLastHidden = true;
         }
         mWin.mExiting = false;
         if (mWin.mRemoveOnExit) {
@@ -357,11 +367,10 @@
     }
 
     boolean finishDrawingLocked() {
-        if (mDrawPending) {
-            if (SHOW_TRANSACTIONS || WindowManagerService.DEBUG_ORIENTATION) Slog.v(
+        if (mDrawState == DRAW_PENDING) {
+            if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Slog.v(
                 TAG, "finishDrawingLocked: " + this + " in " + mSurface);
-            mCommitDrawPending = true;
-            mDrawPending = false;
+            mDrawState = COMMIT_DRAW_PENDING;
             return true;
         }
         return false;
@@ -370,11 +379,10 @@
     // This must be called while inside a transaction.
     boolean commitFinishDrawingLocked(long currentTime) {
         //Slog.i(TAG, "commitFinishDrawingLocked: " + mSurface);
-        if (!mCommitDrawPending) {
+        if (mDrawState != COMMIT_DRAW_PENDING) {
             return false;
         }
-        mCommitDrawPending = false;
-        mWin.mReadyToShow = true;
+        mDrawState = READY_TO_SHOW;
         final boolean starting = mWin.mAttrs.type == TYPE_APPLICATION_STARTING;
         final AppWindowToken atoken = mWin.mAppToken;
         if (atoken == null || atoken.allDrawn || starting) {
@@ -387,11 +395,9 @@
         if (mSurface == null) {
             mReportDestroySurface = false;
             mSurfacePendingDestroy = false;
-            if (WindowManagerService.DEBUG_ORIENTATION) Slog.i(TAG,
+            if (DEBUG_ORIENTATION) Slog.i(TAG,
                     "createSurface " + this + ": DRAW NOW PENDING");
-            mDrawPending = true;
-            mCommitDrawPending = false;
-            mWin.mReadyToShow = false;
+            mDrawState = DRAW_PENDING;
             if (mWin.mAppToken != null) {
                 mWin.mAppToken.allDrawn = false;
             }
@@ -443,6 +449,7 @@
                         mSession.mSurfaceSession, mSession.mPid,
                         attrs.getTitle().toString(),
                         0, w, h, format, flags);
+                mWin.mHasSurface = true;
                 if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG,
                         "  CREATE SURFACE "
                         + mSurface + " IN SESSION "
@@ -452,11 +459,15 @@
                         + Integer.toHexString(flags)
                         + " / " + this);
             } catch (Surface.OutOfResourcesException e) {
+                mWin.mHasSurface = false;
                 Slog.w(TAG, "OutOfResourcesException creating surface");
                 mService.reclaimSomeSurfaceMemoryLocked(this, "create", true);
+                mDrawState = NO_SURFACE;
                 return null;
             } catch (Exception e) {
+                mWin.mHasSurface = false;
                 Slog.e(TAG, "Exception creating surface", e);
+                mDrawState = NO_SURFACE;
                 return null;
             }
 
@@ -489,7 +500,7 @@
                     Slog.w(TAG, "Error creating surface in " + w, e);
                     mService.reclaimSomeSurfaceMemoryLocked(this, "create-init", true);
                 }
-                mWin.mLastHidden = true;
+                mLastHidden = true;
             } finally {
                 Surface.closeTransaction();
                 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
@@ -506,10 +517,8 @@
             mWin.mAppToken.startingDisplayed = false;
         }
 
+        mDrawState = NO_SURFACE;
         if (mSurface != null) {
-            mDrawPending = false;
-            mCommitDrawPending = false;
-            mWin.mReadyToShow = false;
 
             int i = mWin.mChildWindows.size();
             while (i > 0) {
@@ -573,6 +582,7 @@
 
             mSurfaceShown = false;
             mSurface = null;
+            mWin.mHasSurface =false;
         }
     }
 
@@ -746,7 +756,7 @@
         final WindowState w = mWin;
         if (mSurface == null) {
             if (w.mOrientationChanging) {
-                if (WindowManagerService.DEBUG_ORIENTATION) {
+                if (DEBUG_ORIENTATION) {
                     Slog.v(TAG, "Orientation change skips hidden " + w);
                 }
                 w.mOrientationChanging = false;
@@ -819,9 +829,9 @@
         }
 
         if (w.mAttachedHidden || !w.isReadyForDisplay()) {
-            if (!w.mLastHidden) {
+            if (!mLastHidden) {
                 //dump();
-                w.mLastHidden = true;
+                mLastHidden = true;
                 if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
                         "HIDE (performLayout)", null);
                 if (mSurface != null) {
@@ -841,7 +851,7 @@
             // new orientation.
             if (w.mOrientationChanging) {
                 w.mOrientationChanging = false;
-                if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
+                if (DEBUG_ORIENTATION) Slog.v(TAG,
                         "Orientation change skips hidden " + w);
             }
         } else if (mLastLayer != mAnimLayer
@@ -852,7 +862,7 @@
                 || mLastDtDy != mDtDy
                 || w.mLastHScale != w.mHScale
                 || w.mLastVScale != w.mVScale
-                || w.mLastHidden) {
+                || mLastHidden) {
             displayed = true;
             mLastAlpha = mShownAlpha;
             mLastLayer = mAnimLayer;
@@ -877,6 +887,21 @@
                     mSurface.setMatrix(
                         mDsDx*w.mHScale, mDtDx*w.mVScale,
                         mDsDy*w.mHScale, mDtDy*w.mVScale);
+
+                    if (mLastHidden && mDrawState == HAS_DRAWN) {
+                        if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
+                                "SHOW (performLayout)", null);
+                        if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w
+                                + " during relayout");
+                        if (showSurfaceRobustlyLocked()) {
+                            mLastHidden = false;
+                        } else {
+                            w.mOrientationChanging = false;
+                        }
+                    }
+                    if (mSurface != null) {
+                        w.mToken.hasVisible = true;
+                    }
                 } catch (RuntimeException e) {
                     Slog.w(TAG, "Error updating surface in " + w, e);
                     if (!recoveringMemory) {
@@ -884,23 +909,6 @@
                     }
                 }
             }
-
-            if (w.mLastHidden && w.isDrawnLw()
-                    && !w.mReadyToShow) {
-                if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
-                        "SHOW (performLayout)", null);
-                if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w
-                        + " during relayout");
-                if (showSurfaceRobustlyLocked()) {
-                    w.mHasDrawn = true;
-                    w.mLastHidden = false;
-                } else {
-                    w.mOrientationChanging = false;
-                }
-            }
-            if (mSurface != null) {
-                w.mToken.hasVisible = true;
-            }
         } else {
             displayed = true;
         }
@@ -909,18 +917,45 @@
             if (w.mOrientationChanging) {
                 if (!w.isDrawnLw()) {
                     mService.mInnerFields.mOrientationChangeComplete = false;
-                    if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
+                    if (DEBUG_ORIENTATION) Slog.v(TAG,
                             "Orientation continue waiting for draw in " + w);
                 } else {
                     w.mOrientationChanging = false;
-                    if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
-                            "Orientation change complete in " + w);
+                    if (DEBUG_ORIENTATION) Slog.v(TAG, "Orientation change complete in " + w);
                 }
             }
             w.mToken.hasVisible = true;
         }
     }
 
+    void setTransparentRegionHint(final Region region) {
+        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+            ">>> OPEN TRANSACTION setTransparentRegion");
+        Surface.openTransaction();
+        try {
+            if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin,
+                    "transparentRegionHint=" + region, null);
+            mSurface.setTransparentRegionHint(region);
+        } finally {
+            Surface.closeTransaction();
+            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+                    "<<< CLOSE TRANSACTION setTransparentRegion");
+        }
+    }
+
+    void setWallpaperOffset(int left, int top) {
+        Surface.openTransaction();
+        try {
+            mSurfaceX = left;
+            mSurfaceY = top;
+            mSurface.setPosition(left, top);
+        } catch (RuntimeException e) {
+            Slog.w(TAG, "Error positioning surface of " + mWin
+                    + " pos=(" + left + "," + top + ")", e);
+        }
+        Surface.closeTransaction();
+    }
+
     // This must be called while inside a transaction.
     boolean performShowLocked() {
         if (DEBUG_VISIBILITY) {
@@ -930,12 +965,12 @@
                 e.fillInStackTrace();
             }
             Slog.v(TAG, "performShow on " + this
-                    + ": readyToShow=" + mWin.mReadyToShow + " readyForDisplay="
+                    + ": mDrawState=" + mDrawState + " readyForDisplay="
                     + mWin.isReadyForDisplay()
                     + " starting=" + (mWin.mAttrs.type == TYPE_APPLICATION_STARTING), e);
         }
-        if (mWin.mReadyToShow && mWin.isReadyForDisplay()) {
-            if (SHOW_TRANSACTIONS || WindowManagerService.DEBUG_ORIENTATION)
+        if (mDrawState == READY_TO_SHOW && mWin.isReadyForDisplay()) {
+            if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION)
                 WindowManagerService.logSurface(mWin, "SHOW (performShowLocked)", null);
             if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + this
                     + " during animation: policyVis=" + mWin.mPolicyVisibility
@@ -956,9 +991,8 @@
             applyEnterAnimationLocked();
 
             mLastAlpha = -1;
-            mWin.mHasDrawn = true;
-            mWin.mLastHidden = false;
-            mWin.mReadyToShow = false;
+            mLastHidden = false;
+            mDrawState = HAS_DRAWN;
 
             int i = mWin.mChildWindows.size();
             while (i > 0) {
@@ -1051,6 +1085,7 @@
         applyAnimationLocked(transit, true);
     }
 
+    // TODO(cmautner): Move back to WindowState?
     /**
      * Choose the correct animation and set it to the passed WindowState.
      * @param transit If WindowManagerPolicy.TRANSIT_PREVIEW_DONE and the app window has been drawn
@@ -1138,6 +1173,8 @@
         if (mSurface != null) {
             if (dumpAll) {
                 pw.print(prefix); pw.print("mSurface="); pw.println(mSurface);
+                pw.print(prefix); pw.print("mDrawState="); pw.print(mDrawState);
+                pw.print(" mLastHidden="); pw.println(mLastHidden);
             }
             pw.print(prefix); pw.print("Surface: shown="); pw.print(mSurfaceShown);
                     pw.print(" layer="); pw.print(mSurfaceLayer);
@@ -1169,4 +1206,12 @@
         }
     }
 
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer("WindowStateAnimator (");
+        sb.append(mWin.mLastTitle + "): ");
+        sb.append("mSurface " + mSurface);
+        sb.append(", mAnimation " + mAnimation);
+        return sb.toString();
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/ApnContext.java b/telephony/java/com/android/internal/telephony/ApnContext.java
index 8aeee87..80d5044 100644
--- a/telephony/java/com/android/internal/telephony/ApnContext.java
+++ b/telephony/java/com/android/internal/telephony/ApnContext.java
@@ -17,6 +17,9 @@
 package com.android.internal.telephony;
 
 import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -207,4 +210,19 @@
     protected void log(String s) {
         Log.d(LOG_TAG, "[ApnContext] " + s);
     }
+
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("ApnContext:");
+        pw.println(" mApnType=" + mApnType);
+        pw.println(" mState=" + mState);
+        pw.println(" mWaitingApns=" + mWaitingApns);
+        pw.println(" mWaitingApnsPermanentFailureCountDown=" +
+                            mWaitingApnsPermanentFailureCountDown);
+        pw.println(" mApnSetting=" + mApnSetting);
+        pw.println(" mDataConnection=" + mDataConnection);
+        pw.println(" mDataConnectionAc=" + mDataConnectionAc);
+        pw.println(" mReason=" + mReason);
+        pw.println(" mDataEnabled=" + mDataEnabled);
+        pw.println(" mDependencyMet=" + mDependencyMet);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/CallTracker.java b/telephony/java/com/android/internal/telephony/CallTracker.java
index 958481c..62caf01 100644
--- a/telephony/java/com/android/internal/telephony/CallTracker.java
+++ b/telephony/java/com/android/internal/telephony/CallTracker.java
@@ -25,6 +25,9 @@
 
 import com.android.internal.telephony.CommandException;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 
 /**
  * {@hide}
@@ -170,4 +173,10 @@
 
     protected abstract void log(String msg);
 
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("CallTracker:");
+        pw.println(" pendingOperations=" + pendingOperations);
+        pw.println(" needsPoll=" + needsPoll);
+        pw.println(" lastRelevantPoll=" + lastRelevantPoll);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 238afbe..486a924 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -32,6 +32,8 @@
 import android.os.SystemProperties;
 import android.text.TextUtils;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -1185,4 +1187,27 @@
         sendMessage(obtainMessage(EVENT_DISCONNECT_ALL,
                 new DisconnectParams(reason, onCompletedMsg)));
     }
+
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("DataConnection name=" + getName() + ":");
+        pw.println(" mApnList=" + mApnList);
+        pw.println(" mDataConnectionTracker=" + mDataConnectionTracker);
+        pw.println(" mApn=" + mApn);
+        pw.println(" mTag=" + mTag);
+        pw.println(" phone=" + phone);
+        pw.println(" mRilVersion=" + mRilVersion);
+        pw.println(" cid=" + cid);
+        pw.println(" mLinkProperties=" + mLinkProperties);
+        pw.println(" mCapabilities=" + mCapabilities);
+        pw.println(" createTime=" + createTime);
+        pw.println(" lastFailTime=" + lastFailTime);
+        pw.println(" lastFailCause=" + lastFailCause);
+        pw.println(" mRetryOverride=" + mRetryOverride);
+        pw.println(" mRefCount=" + mRefCount);
+        pw.println(" userData=" + userData);
+        pw.println(" total messages=" + getProcessedMessagesCount());
+        for (int i=0; i < getProcessedMessagesSize(); i++) {
+            pw.printf("  msg[%d]=%s\n", i, getProcessedMessageInfo(i));
+        }
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index fa90f1c..55f2ca3 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -49,8 +49,12 @@
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Map.Entry;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -1193,4 +1197,80 @@
             dc.resetRetryCount();
         }
     }
+
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("DataConnectionTracker:");
+        pw.println(" mInternalDataEnabled=" + mInternalDataEnabled);
+        pw.println(" mUserDataEnabled=" + mUserDataEnabled);
+        pw.println(" sPolicyDataEnabed=" + sPolicyDataEnabled);
+        pw.println(" dataEnabled:");
+        for(int i=0; i < dataEnabled.length; i++) {
+            pw.printf("  dataEnabled[%d]=%b\n", i, dataEnabled[i]);
+        }
+        pw.flush();
+        pw.println(" enabledCount=" + enabledCount);
+        pw.println(" mRequestedApnType=" + mRequestedApnType);
+        pw.println(" mPhone=" + mPhone.getPhoneName());
+        pw.println(" mActivity=" + mActivity);
+        pw.println(" mState=" + mState);
+        pw.println(" mTxPkts=" + mTxPkts);
+        pw.println(" mRxPkts=" + mRxPkts);
+        pw.println(" mNetStatPollPeriod=" + mNetStatPollPeriod);
+        pw.println(" mNetStatPollEnabled=" + mNetStatPollEnabled);
+        pw.println(" mDataStallTxRxSum=" + mDataStallTxRxSum);
+        pw.println(" mDataStallAlarmTag=" + mDataStallAlarmTag);
+        pw.println(" mSentSinceLastRecv=" + mSentSinceLastRecv);
+        pw.println(" mNoRecvPollCount=" + mNoRecvPollCount);
+        pw.println(" mIsWifiConnected=" + mIsWifiConnected);
+        pw.println(" mReconnectIntent=" + mReconnectIntent);
+        pw.println(" mCidActive=" + mCidActive);
+        pw.println(" mAutoAttachOnCreation=" + mAutoAttachOnCreation);
+        pw.println(" mIsScreenOn=" + mIsScreenOn);
+        pw.println(" mUniqueIdGenerator=" + mUniqueIdGenerator);
+        pw.flush();
+        pw.println(" ***************************************");
+        Set<Entry<Integer, DataConnection> > mDcSet = mDataConnections.entrySet();
+        pw.println(" mDataConnections: count=" + mDcSet.size());
+        for (Entry<Integer, DataConnection> entry : mDcSet) {
+            pw.printf(" *** mDataConnection[%d] \n", entry.getKey());
+            entry.getValue().dump(fd, pw, args);
+        }
+        pw.println(" ***************************************");
+        pw.flush();
+        Set<Entry<String, Integer>> mApnToDcIdSet = mApnToDataConnectionId.entrySet();
+        pw.println(" mApnToDataConnectonId size=" + mApnToDcIdSet.size());
+        for (Entry<String, Integer> entry : mApnToDcIdSet) {
+            pw.printf(" mApnToDataConnectonId[%s]=%d\n", entry.getKey(), entry.getValue());
+        }
+        pw.println(" ***************************************");
+        pw.flush();
+        if (mApnContexts != null) {
+            Set<Entry<String, ApnContext>> mApnContextsSet = mApnContexts.entrySet();
+            pw.println(" mApnContexts size=" + mApnContextsSet.size());
+            for (Entry<String, ApnContext> entry : mApnContextsSet) {
+                pw.printf(" *** mApnContexts[%s]:\n", entry.getKey());
+                entry.getValue().dump(fd, pw, args);
+            }
+            pw.println(" ***************************************");
+        } else {
+            pw.println(" mApnContexts=null");
+        }
+        pw.flush();
+        pw.println(" mActiveApn=" + mActiveApn);
+        if (mAllApns != null) {
+            pw.println(" mAllApns size=" + mAllApns.size());
+            for (int i=0; i < mAllApns.size(); i++) {
+                pw.printf(" mAllApns[%d]: %s\n", i, mAllApns.get(i));
+            }
+            pw.flush();
+        } else {
+            pw.println(" mAllApns=null");
+        }
+        pw.println(" mPreferredApn=" + mPreferredApn);
+        pw.println(" mIsPsRestricted=" + mIsPsRestricted);
+        pw.println(" mIsDisposed=" + mIsDisposed);
+        pw.println(" mIntentReceiver=" + mIntentReceiver);
+        pw.println(" mDataRoamingSettingObserver=" + mDataRoamingSettingObserver);
+        pw.flush();
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/DebugService.java b/telephony/java/com/android/internal/telephony/DebugService.java
new file mode 100644
index 0000000..29fea6e
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/DebugService.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * A debug service that will dump telephony's state
+ *
+ * Currently this "Service" has a proxy in the phone app
+ * com.android.phone.TelephonyDebugService which actually
+ * invokes the dump method.
+ */
+public class DebugService {
+    private static String TAG = "DebugService";
+
+    /** Constructor */
+    public DebugService() {
+        log("DebugService:");
+    }
+
+    /**
+     * Dump the state of various objects, add calls to other objects as desired.
+     */
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        log("dump: +");
+        PhoneProxy phoneProxy = null;
+        PhoneBase phoneBase = null;
+
+        try {
+            phoneProxy = (PhoneProxy) PhoneFactory.getDefaultPhone();
+        } catch (Exception e) {
+            pw.println("Telephony DebugService: Could not getDefaultPhone e=" + e);
+            return;
+        }
+        try {
+            phoneBase = (PhoneBase)phoneProxy.getActivePhone();
+        } catch (Exception e) {
+            pw.println("Telephony DebugService: Could not PhoneBase e=" + e);
+            return;
+        }
+
+        /**
+         * Surround each of the sub dump's with try/catch so even
+         * if one fails we'll be able to dump the next ones.
+         */
+        pw.println();
+        pw.println("++++++++++++++++++++++++++++++++");
+        pw.flush();
+        try {
+            phoneBase.dump(fd, pw, args);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        pw.flush();
+        pw.println("++++++++++++++++++++++++++++++++");
+        try {
+            phoneBase.mDataConnectionTracker.dump(fd, pw, args);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        pw.flush();
+        pw.println("++++++++++++++++++++++++++++++++");
+        try {
+            phoneBase.getServiceStateTracker().dump(fd, pw, args);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        pw.flush();
+        pw.println("++++++++++++++++++++++++++++++++");
+        try {
+            phoneBase.getCallTracker().dump(fd, pw, args);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        pw.flush();
+        pw.println("++++++++++++++++++++++++++++++++");
+        try {
+            ((RIL)phoneBase.mCM).dump(fd, pw, args);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        pw.flush();
+        pw.println("++++++++++++++++++++++++++++++++");
+        log("dump: -");
+    }
+
+    private static void log(String s) {
+        Log.d(TAG, "DebugService " + s);
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 3aa53eef..1b4cb15 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -42,6 +42,8 @@
 import com.android.internal.telephony.test.SimulatedRadioControl;
 import com.android.internal.telephony.gsm.SIMRecords;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.Locale;
 import java.util.concurrent.atomic.AtomicReference;
 
@@ -1144,4 +1146,43 @@
     public UsimServiceTable getUsimServiceTable() {
         return mIccRecords.getUsimServiceTable();
     }
+
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("PhoneBase:");
+        pw.println(" mCM=" + mCM);
+        pw.println(" mDnsCheckDisabled=" + mDnsCheckDisabled);
+        pw.println(" mDataConnectionTracker=" + mDataConnectionTracker);
+        pw.println(" mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing);
+        pw.println(" mCallRingContinueToken=" + mCallRingContinueToken);
+        pw.println(" mCallRingDelay=" + mCallRingDelay);
+        pw.println(" mIsTheCurrentActivePhone=" + mIsTheCurrentActivePhone);
+        pw.println(" mIsVoiceCapable=" + mIsVoiceCapable);
+        pw.println(" mIccRecords=" + mIccRecords);
+        pw.println(" mIccCard=" + mIccCard.get());
+        pw.println(" mSmsStorageMonitor=" + mSmsStorageMonitor);
+        pw.println(" mSmsUsageMonitor=" + mSmsUsageMonitor);
+        pw.println(" mSMS=" + mSMS);
+        pw.flush();
+        pw.println(" mLooper=" + mLooper);
+        pw.println(" mContext=" + mContext);
+        pw.println(" mNotifier=" + mNotifier);
+        pw.println(" mSimulatedRadioControl=" + mSimulatedRadioControl);
+        pw.println(" mUnitTestMode=" + mUnitTestMode);
+        pw.println(" isDnsCheckDisabled()=" + isDnsCheckDisabled());
+        pw.println(" getUnitTestMode()=" + getUnitTestMode());
+        pw.println(" getState()=" + getState());
+        pw.println(" getIccSerialNumber()=" + getIccSerialNumber());
+        pw.println(" getIccRecordsLoaded()=" + getIccRecordsLoaded());
+        pw.println(" getMessageWaitingIndicator()=" + getMessageWaitingIndicator());
+        pw.println(" getCallForwardingIndicator()=" + getCallForwardingIndicator());
+        pw.println(" isInEmergencyCall()=" + isInEmergencyCall());
+        pw.flush();
+        pw.println(" isInEcm()=" + isInEcm());
+        pw.println(" getPhoneName()=" + getPhoneName());
+        pw.println(" getPhoneType()=" + getPhoneType());
+        pw.println(" getVoiceMessageCount()=" + getVoiceMessageCount());
+        pw.println(" getActiveApnTypes()=" + getActiveApnTypes());
+        pw.println(" isDataConnectivityPossible()=" + isDataConnectivityPossible());
+        pw.println(" needsOtaServiceProvisioning=" + needsOtaServiceProvisioning());
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index cf96ab2..b14f6c8 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -56,8 +56,10 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.DataInputStream;
+import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -3833,4 +3835,27 @@
         if (RILJ_LOGD) riljLog("testingEmergencyCall");
         mTestingEmergencyCall.set(true);
     }
+
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("RIL:");
+        pw.println(" mSocket=" + mSocket);
+        pw.println(" mSenderThread=" + mSenderThread);
+        pw.println(" mSender=" + mSender);
+        pw.println(" mReceiverThread=" + mReceiverThread);
+        pw.println(" mReceiver=" + mReceiver);
+        pw.println(" mWakeLock=" + mWakeLock);
+        pw.println(" mWakeLockTimeout=" + mWakeLockTimeout);
+        synchronized (mRequestsList) {
+          pw.println(" mRequestMessagesPending=" + mRequestMessagesPending);
+          pw.println(" mRequestMessagesWaiting=" + mRequestMessagesWaiting);
+            int count = mRequestsList.size();
+            pw.println(" mRequestList count=" + count);
+            for (int i = 0; i < count; i++) {
+                RILRequest rr = mRequestsList.get(i);
+                pw.println("  [" + rr.mSerial + "] " + requestToString(rr.mRequest));
+            }
+        }
+        pw.println(" mLastNITZTimeInfo=" + mLastNITZTimeInfo);
+        pw.println(" mTestingEmergencyCall=" + mTestingEmergencyCall.get());
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
index fd39e04..75eb226 100644
--- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -24,6 +24,9 @@
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 /**
  * {@hide}
  */
@@ -459,4 +462,19 @@
         // This will effectively cancel the rest of the poll requests.
         pollingContext = new int[1];
     }
+
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("ServiceStateTracker:");
+        pw.println(" ss=" + ss);
+        pw.println(" newSS=" + newSS);
+        pw.println(" mSignalStrength=" + mSignalStrength);
+        pw.println(" mRestrictedState=" + mRestrictedState);
+        pw.println(" pollingContext=" + pollingContext);
+        pw.println(" mDesiredPowerState=" + mDesiredPowerState);
+        pw.println(" mRilRadioTechnology=" + mRilRadioTechnology);
+        pw.println(" mNewRilRadioTechnology=" + mNewRilRadioTechnology);
+        pw.println(" dontPollSignalStrength=" + dontPollSignalStrength);
+        pw.println(" mPendingRadioPowerOffAfterDataOff=" + mPendingRadioPowerOffAfterDataOff);
+        pw.println(" mPendingRadioPowerOffAfterDataOffTag=" + mPendingRadioPowerOffAfterDataOffTag);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
index 110d8bf..d99a625 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
@@ -39,6 +39,9 @@
 import com.android.internal.telephony.ims.IsimRecords;
 import com.android.internal.telephony.uicc.UiccController;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 public class CDMALTEPhone extends CDMAPhone {
     static final String LOG_TAG = "CDMA";
 
@@ -259,4 +262,11 @@
     protected void log(String s) {
             Log.d(LOG_TAG, "[CDMALTEPhone] " + s);
     }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("CDMALTEPhone extends:");
+        super.dump(fd, pw, args);
+        pw.println(" m3gppSMS=" + m3gppSMS);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index bb00d4b..ed0081b 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -66,6 +66,8 @@
 import com.android.internal.telephony.cat.CatService;
 import com.android.internal.telephony.uicc.UiccController;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.regex.Matcher;
@@ -81,6 +83,7 @@
 public class CDMAPhone extends PhoneBase {
     static final String LOG_TAG = "CDMA";
     private static final boolean DBG = true;
+    private static final boolean VDBG = false; /* STOP SHIP if true */
 
     // Default Emergency Callback Mode exit timer
     private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
@@ -1471,4 +1474,32 @@
         if (DBG)
             Log.d(LOG_TAG, "[CDMAPhone] " + s);
     }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("CDMAPhone extends:");
+        super.dump(fd, pw, args);
+        pw.println(" mVmNumber=" + mVmNumber);
+        pw.println(" mCT=" + mCT);
+        pw.println(" mSST=" + mSST);
+        pw.println(" mCdmaSSM=" + mCdmaSSM);
+        pw.println(" mPendingMmis=" + mPendingMmis);
+        pw.println(" mRuimPhoneBookInterfaceManager=" + mRuimPhoneBookInterfaceManager);
+        pw.println(" mRuimSmsInterfaceManager=" + mRuimSmsInterfaceManager);
+        pw.println(" mCdmaSubscriptionSource=" + mCdmaSubscriptionSource);
+        pw.println(" mSubInfo=" + mSubInfo);
+        pw.println(" mEriManager=" + mEriManager);
+        pw.println(" mWakeLock=" + mWakeLock);
+        pw.println(" mIsPhoneInEcmState=" + mIsPhoneInEcmState);
+        if (VDBG) pw.println(" mImei=" + mImei);
+        if (VDBG) pw.println(" mImeiSv=" + mImeiSv);
+        if (VDBG) pw.println(" mEsn=" + mEsn);
+        if (VDBG) pw.println(" mMeid=" + mMeid);
+        pw.println(" mCarrierOtaSpNumSchema=" + mCarrierOtaSpNumSchema);
+        pw.println(" getCdmaEriIconIndex()=" + getCdmaEriIconIndex());
+        pw.println(" getCdmaEriIconMode()=" + getCdmaEriIconMode());
+        pw.println(" getCdmaEriText()=" + getCdmaEriText());
+        pw.println(" isMinInfoReady()=" + isMinInfoReady());
+        pw.println(" isCspPlmnEnabled()=" + isCspPlmnEnabled());
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
index f918dce..af92b08 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -34,6 +34,8 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.TelephonyProperties;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -1129,4 +1131,32 @@
         Log.d(LOG_TAG, "[CdmaCallTracker] " + msg);
     }
 
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("GsmCallTracker extends:");
+        super.dump(fd, pw, args);
+        pw.println("droppedDuringPoll: length=" + connections.length);
+        for(int i=0; i < connections.length; i++) {
+            pw.printf(" connections[%d]=%s\n", i, connections[i]);
+        }
+        pw.println(" voiceCallEndedRegistrants=" + voiceCallEndedRegistrants);
+        pw.println(" voiceCallStartedRegistrants=" + voiceCallStartedRegistrants);
+        pw.println(" callWaitingRegistrants=" + callWaitingRegistrants);
+        pw.println("droppedDuringPoll: size=" + droppedDuringPoll.size());
+        for(int i = 0; i < droppedDuringPoll.size(); i++) {
+            pw.printf( " droppedDuringPoll[%d]=%s\n", i, droppedDuringPoll.get(i));
+        }
+        pw.println(" ringingCall=" + ringingCall);
+        pw.println(" foregroundCall=" + foregroundCall);
+        pw.println(" backgroundCall=" + backgroundCall);
+        pw.println(" pendingMO=" + pendingMO);
+        pw.println(" hangupPendingMO=" + hangupPendingMO);
+        pw.println(" pendingCallInEcm=" + pendingCallInEcm);
+        pw.println(" mIsInEmergencyCall=" + mIsInEmergencyCall);
+        pw.println(" phone=" + phone);
+        pw.println(" desiredMute=" + desiredMute);
+        pw.println(" pendingCallClirMode=" + pendingCallClirMode);
+        pw.println(" state=" + state);
+        pw.println(" mIsEcmTimerCanceled=" + mIsEcmTimerCanceled);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
index 64d018e..4ef05ea 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
@@ -25,6 +25,9 @@
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.RetryManager;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 /**
  * {@hide}
  */
@@ -114,4 +117,10 @@
     protected void log(String s) {
         Log.d(LOG_TAG, "[" + getName() + "] " + s);
     }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("CdmaDataConnection extends:");
+        super.dump(fd, pw, args);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 5f1a014..7e5e707 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -46,6 +46,8 @@
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.telephony.RILConstants;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 
 /**
@@ -1017,4 +1019,18 @@
     protected void loge(String s) {
         Log.e(LOG_TAG, "[CdmaDCT] " + s);
     }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("CdmaDataConnectionTracker extends:");
+        super.dump(fd, pw, args);
+        pw.println(" mCdmaPhone=" + mCdmaPhone);
+        pw.println(" mCdmaSSM=" + mCdmaSSM);
+        pw.println(" mPendingDataConnection=" + mPendingDataConnection);
+        pw.println(" mPendingRestartRadio=" + mPendingRestartRadio);
+        pw.println(" mSupportedApnTypes=" + mSupportedApnTypes);
+        pw.println(" mDefaultApnTypes=" + mDefaultApnTypes);
+        pw.println(" mDunApnTypes=" + mDunApnTypes);
+        pw.println(" mDefaultApnId=" + mDefaultApnId);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
index 09008cd..98a106a0 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -36,6 +36,9 @@
 
 import com.android.internal.telephony.gsm.GsmDataConnectionTracker;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker {
     CDMALTEPhone mCdmaLtePhone;
 
@@ -519,4 +522,12 @@
     protected void loge(String s) {
         Log.e(LOG_TAG, "[CdmaLteSST] " + s);
     }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("CdmaLteServiceStateTracker extends:");
+        super.dump(fd, pw, args);
+        pw.println(" mCdmaLtePhone=" + mCdmaLtePhone);
+        pw.println(" mLteSS=" + mLteSS);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 9ec56fc..9f27696 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -54,6 +54,8 @@
 import android.util.Log;
 import android.util.TimeUtils;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Date;
@@ -1665,4 +1667,43 @@
     protected void loge(String s) {
         Log.e(LOG_TAG, "[CdmaSST] " + s);
     }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("CdmaServiceStateTracker extends:");
+        super.dump(fd, pw, args);
+        pw.println(" phone=" + phone);
+        pw.println(" cellLoc=" + cellLoc);
+        pw.println(" newCellLoc=" + newCellLoc);
+        pw.println(" mCurrentOtaspMode=" + mCurrentOtaspMode);
+        pw.println(" mCdmaRoaming=" + mCdmaRoaming);
+        pw.println(" mRoamingIndicator=" + mRoamingIndicator);
+        pw.println(" mIsInPrl=" + mIsInPrl);
+        pw.println(" mDefaultRoamingIndicator=" + mDefaultRoamingIndicator);
+        pw.println(" mDataConnectionState=" + mDataConnectionState);
+        pw.println(" mNewDataConnectionState=" + mNewDataConnectionState);
+        pw.println(" mRegistrationState=" + mRegistrationState);
+        pw.println(" mNeedFixZone=" + mNeedFixZone);
+        pw.println(" mZoneOffset=" + mZoneOffset);
+        pw.println(" mZoneDst=" + mZoneDst);
+        pw.println(" mZoneTime=" + mZoneTime);
+        pw.println(" mGotCountryCode=" + mGotCountryCode);
+        pw.println(" mSavedTimeZone=" + mSavedTimeZone);
+        pw.println(" mSavedTime=" + mSavedTime);
+        pw.println(" mSavedAtTime=" + mSavedAtTime);
+        pw.println(" mNeedToRegForRuimLoaded=" + mNeedToRegForRuimLoaded);
+        pw.println(" mWakeLock=" + mWakeLock);
+        pw.println(" mCurPlmn=" + mCurPlmn);
+        pw.println(" mMdn=" + mMdn);
+        pw.println(" mHomeSystemId=" + mHomeSystemId);
+        pw.println(" mHomeNetworkId=" + mHomeNetworkId);
+        pw.println(" mMin=" + mMin);
+        pw.println(" mPrlVersion=" + mPrlVersion);
+        pw.println(" mIsMinInfoReady=" + mIsMinInfoReady);
+        pw.println(" isEriTextLoaded=" + isEriTextLoaded);
+        pw.println(" isSubscriptionFromRuim=" + isSubscriptionFromRuim);
+        pw.println(" mCdmaSSM=" + mCdmaSSM);
+        pw.println(" mRegistrationDeniedReason=" + mRegistrationDeniedReason);
+        pw.println(" currentCarrier=" + currentCarrier);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index be13c35..6e9cd51 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -74,7 +74,9 @@
 import com.android.internal.telephony.IccVmNotSupportedException;
 import com.android.internal.telephony.ServiceStateTracker;
 
+import java.io.FileDescriptor;
 import java.io.IOException;
+import java.io.PrintWriter;
 import java.net.InetSocketAddress;
 import java.net.ServerSocket;
 import java.net.Socket;
@@ -90,6 +92,7 @@
     // log.  (Use "adb logcat -b radio" to see them.)
     static final String LOG_TAG = "GSM";
     private static final boolean LOCAL_DEBUG = true;
+    private static final boolean VDBG = false; /* STOP SHIP if true */
 
     // Key used to read/write current ciphering state
     public static final String CIPHERING_KEY = "ciphering_key";
@@ -1487,4 +1490,18 @@
         mIccRecords.unregisterForRecordsLoaded(this);
     }
 
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("GSMPhone extends:");
+        super.dump(fd, pw, args);
+        pw.println(" mCT=" + mCT);
+        pw.println(" mSST=" + mSST);
+        pw.println(" mPendingMMIs=" + mPendingMMIs);
+        pw.println(" mSimPhoneBookIntManager=" + mSimPhoneBookIntManager);
+        pw.println(" mSimSmsIntManager=" + mSimSmsIntManager);
+        pw.println(" mSubInfo=" + mSubInfo);
+        if (VDBG) pw.println(" mImei=" + mImei);
+        if (VDBG) pw.println(" mImeiSv=" + mImeiSv);
+        pw.println(" mVmNumber=" + mVmNumber);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
index b4e0775..e86d853 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
@@ -43,6 +43,8 @@
 import com.android.internal.telephony.gsm.GsmCall;
 import com.android.internal.telephony.gsm.GsmConnection;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.List;
 import java.util.ArrayList;
 
@@ -922,4 +924,28 @@
     protected void log(String msg) {
         Log.d(LOG_TAG, "[GsmCallTracker] " + msg);
     }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("GsmCallTracker extends:");
+        super.dump(fd, pw, args);
+        pw.println("connections: length=" + connections.length);
+        for(int i=0; i < connections.length; i++) {
+            pw.printf("  connections[%d]=%s\n", i, connections[i]);
+        }
+        pw.println(" voiceCallEndedRegistrants=" + voiceCallEndedRegistrants);
+        pw.println(" voiceCallStartedRegistrants=" + voiceCallStartedRegistrants);
+        pw.println(" droppedDuringPoll: size=" + droppedDuringPoll.size());
+        for(int i = 0; i < droppedDuringPoll.size(); i++) {
+            pw.printf( "  droppedDuringPoll[%d]=%s\n", i, droppedDuringPoll.get(i));
+        }
+        pw.println(" ringingCall=" + ringingCall);
+        pw.println(" foregroundCall=" + foregroundCall);
+        pw.println(" backgroundCall=" + backgroundCall);
+        pw.println(" pendingMO=" + pendingMO);
+        pw.println(" hangupPendingMO=" + hangupPendingMO);
+        pw.println(" phone=" + phone);
+        pw.println(" desiredMute=" + desiredMute);
+        pw.println(" state=" + state);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
index 4956ef4..fec0158 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
@@ -28,6 +28,9 @@
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.RetryManager;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 /**
  * {@hide}
  */
@@ -153,4 +156,11 @@
 
         return Patterns.IP_ADDRESS.matcher(address).matches();
     }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("GsmDataConnection extends:");
+        super.dump(fd, pw, args);
+        pw.println(" mProfileId=" + mProfileId);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index d1873eb..40ee58c 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -65,6 +65,8 @@
 import com.android.internal.telephony.RetryManager;
 import com.android.internal.util.AsyncChannel;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
@@ -2562,4 +2564,16 @@
     protected void loge(String s) {
         Log.e(LOG_TAG, "[GsmDCT] " + s);
     }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("GsmDataConnectionTracker extends:");
+        super.dump(fd, pw, args);
+        pw.println(" RADIO_TESTS=" + RADIO_TESTS);
+        pw.println(" mReregisterOnReconnectFailure=" + mReregisterOnReconnectFailure);
+        pw.println(" mResolver=" + mResolver);
+        pw.println(" canSetPreferApn=" + canSetPreferApn);
+        pw.println(" mApnObserver=" + mApnObserver);
+        pw.println(" getOverallState=" + getOverallState());
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 080d90c..662f1f6 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -59,6 +59,8 @@
 import android.util.Log;
 import android.util.TimeUtils;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -1681,4 +1683,40 @@
     private static void sloge(String s) {
         Log.e(LOG_TAG, "[GsmSST] " + s);
     }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("GsmServiceStateTracker extends:");
+        super.dump(fd, pw, args);
+        pw.println(" phone=" + phone);
+        pw.println(" cellLoc=" + cellLoc);
+        pw.println(" newCellLoc=" + newCellLoc);
+        pw.println(" mPreferredNetworkType=" + mPreferredNetworkType);
+        pw.println(" gprsState=" + gprsState);
+        pw.println(" newGPRSState=" + newGPRSState);
+        pw.println(" mMaxDataCalls=" + mMaxDataCalls);
+        pw.println(" mNewMaxDataCalls=" + mNewMaxDataCalls);
+        pw.println(" mReasonDataDenied=" + mReasonDataDenied);
+        pw.println(" mNewReasonDataDenied=" + mNewReasonDataDenied);
+        pw.println(" mGsmRoaming=" + mGsmRoaming);
+        pw.println(" mDataRoaming=" + mDataRoaming);
+        pw.println(" mEmergencyOnly=" + mEmergencyOnly);
+        pw.println(" mNeedFixZone=" + mNeedFixZone);
+        pw.println(" mZoneOffset=" + mZoneOffset);
+        pw.println(" mZoneDst=" + mZoneDst);
+        pw.println(" mZoneTime=" + mZoneTime);
+        pw.println(" mGotCountryCode=" + mGotCountryCode);
+        pw.println(" mNitzUpdatedTime=" + mNitzUpdatedTime);
+        pw.println(" mSavedTimeZone=" + mSavedTimeZone);
+        pw.println(" mSavedTime=" + mSavedTime);
+        pw.println(" mSavedAtTime=" + mSavedAtTime);
+        pw.println(" mNeedToRegForSimLoaded=" + mNeedToRegForSimLoaded);
+        pw.println(" mStartedGprsRegCheck=" + mStartedGprsRegCheck);
+        pw.println(" mReportedGprsNoReg=" + mReportedGprsNoReg);
+        pw.println(" mNotification=" + mNotification);
+        pw.println(" mWakeLock=" + mWakeLock);
+        pw.println(" curSpn=" + curSpn);
+        pw.println(" curPlmn=" + curPlmn);
+        pw.println(" curSpnRule=" + curSpnRule);
+    }
 }
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index b310d93..f4c0841 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -638,7 +638,6 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
-        
 
         <activity
                 android:name="StackActivity"
@@ -649,5 +648,14 @@
             </intent-filter>
         </activity>
 
+        <activity
+                android:name="TransformsAndAnimationsActivity"
+                android:label="_TransformAnim">
+            <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/HwAccelerationTest/res/layout/transforms_and_animations.xml b/tests/HwAccelerationTest/res/layout/transforms_and_animations.xml
new file mode 100644
index 0000000..1595502
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/transforms_and_animations.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <LinearLayout android:orientation="horizontal"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content">
+
+        <CheckBox android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="None"
+                android:checked="true"
+                android:id="@+id/layersNoneCB"/>
+
+        <CheckBox android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:text="Hardware"
+                  android:id="@+id/layersHwCB"/>
+
+        <CheckBox android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:text="Software"
+                  android:id="@+id/layersSwCB"/>
+
+    </LinearLayout>
+
+    <LinearLayout android:orientation="horizontal"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content">
+
+        <Button android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="1"
+                android:id="@+id/button1"/>
+
+        <Button android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="2"
+                android:id="@+id/button2"/>
+
+        <Button android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="3"
+                android:id="@+id/button3"/>
+
+    </LinearLayout>
+
+    <LinearLayout android:orientation="horizontal"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content">
+
+        <Button android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="1a"
+                android:id="@+id/button1a"/>
+
+        <Button android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="2a"
+                android:id="@+id/button2a"/>
+
+        <Button android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="3a"
+                android:id="@+id/button3a"/>
+
+    </LinearLayout>
+
+    <LinearLayout android:orientation="horizontal"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content">
+
+        <Button android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="1b"
+                android:id="@+id/button1b"/>
+
+        <Button android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="2b"
+                android:id="@+id/button2b"/>
+
+        <Button android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="3b"
+                android:id="@+id/button3b"/>
+
+    </LinearLayout>
+
+    <view class="com.android.test.hwui.TransformsAndAnimationsActivity$MyLayout"
+                  android:orientation="horizontal"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content">
+
+        <Button android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="4"
+                android:id="@+id/button4"/>
+
+        <Button android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="5"
+                android:id="@+id/button5"/>
+
+        <Button android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="6"
+                android:id="@+id/button6"/>
+
+    </view>
+
+    <LinearLayout android:orientation="horizontal"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content">
+
+        <Button android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="7"
+                android:id="@+id/button7"/>
+
+        <Button android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="8"
+                android:id="@+id/button8"/>
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TransformsAndAnimationsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TransformsAndAnimationsActivity.java
new file mode 100644
index 0000000..684d179
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TransformsAndAnimationsActivity.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.hwui;
+
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.Transformation;
+import android.view.animation.TranslateAnimation;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.LinearLayout;
+
+public class TransformsAndAnimationsActivity extends Activity {
+    Button button1;
+    Button button2;
+    Button button3;
+    Button button1a;
+    Button button2a;
+    Button button3a;
+    Button button1b;
+    Button button2b;
+    Button button3b;
+    Button button4;
+    Button button5;
+    Button button6;
+    Button button7;
+    Button button8;
+    CheckBox layersNoneCB;
+    CheckBox layersHardwareCB;
+    CheckBox layersSoftwareCB;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.transforms_and_animations);
+
+        button1 = (Button) findViewById(R.id.button1);
+        button2 = (Button) findViewById(R.id.button2);
+        button3 = (Button) findViewById(R.id.button3);
+        button1a = (Button) findViewById(R.id.button1a);
+        button2a = (Button) findViewById(R.id.button2a);
+        button3a = (Button) findViewById(R.id.button3a);
+        button1b = (Button) findViewById(R.id.button1b);
+        button2b = (Button) findViewById(R.id.button2b);
+        button3b = (Button) findViewById(R.id.button3b);
+        button4 = (Button) findViewById(R.id.button4);
+        button5 = (Button) findViewById(R.id.button5);
+        button6 = (Button) findViewById(R.id.button6);
+        button7 = (Button) findViewById(R.id.button7);
+        button8 = (Button) findViewById(R.id.button8);
+        layersNoneCB = (CheckBox) findViewById(R.id.layersNoneCB);
+        layersHardwareCB = (CheckBox) findViewById(R.id.layersHwCB);
+        layersSoftwareCB = (CheckBox) findViewById(R.id.layersSwCB);
+
+        layersNoneCB.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener() {
+            @Override
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                if (isChecked) {
+                    setLayerType(View.LAYER_TYPE_NONE);
+                    layersHardwareCB.setChecked(false);
+                    layersSoftwareCB.setChecked(false);
+                }
+            }
+        });
+
+        layersSoftwareCB.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener() {
+            @Override
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                if (isChecked) {
+                    setLayerType(View.LAYER_TYPE_SOFTWARE);
+                    layersHardwareCB.setChecked(false);
+                    layersNoneCB.setChecked(false);
+                }
+            }
+        });
+
+        layersHardwareCB.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener() {
+            @Override
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                if (isChecked) {
+                    setLayerType(View.LAYER_TYPE_HARDWARE);
+                    layersNoneCB.setChecked(false);
+                    layersSoftwareCB.setChecked(false);
+                }
+            }
+        });
+
+        button1a.setAlpha(.5f);
+        button2a.setAlpha(.5f);
+        button3a.setAlpha(.5f);
+        button3.setTranslationX(50);
+        button7.setTranslationX(50);
+        button8.setTranslationX(50);
+
+        final AlphaAnimation alphaAnim = new AlphaAnimation(1, 0);
+        alphaAnim.setDuration(1000);
+        alphaAnim.setRepeatCount(Animation.INFINITE);
+        alphaAnim.setRepeatMode(Animation.REVERSE);
+
+        final TranslateAnimation transAnim = new TranslateAnimation(0, -50, 0, 0);
+        transAnim.setDuration(1000);
+        transAnim.setRepeatCount(Animation.INFINITE);
+        transAnim.setRepeatMode(Animation.REVERSE);
+        
+        getWindow().getDecorView().postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                button1.startAnimation(alphaAnim);
+                button2.startAnimation(alphaAnim);
+                button3.startAnimation(alphaAnim);
+
+                button1a.startAnimation(alphaAnim);
+                button2a.startAnimation(alphaAnim);
+                button3a.startAnimation(alphaAnim);
+
+                button1b.startAnimation(alphaAnim);
+                button2b.startAnimation(alphaAnim);
+                button3b.startAnimation(alphaAnim);
+                startAnimator(button1b);
+                startAnimator(button2b);
+                startAnimator(button3b);
+
+                button7.startAnimation(transAnim);
+                button8.startAnimation(transAnim);
+            }
+        }, 2000);
+    }
+
+    private void setLayerType(int layerType) {
+        button1.setLayerType(layerType, null);
+        button2.setLayerType(layerType, null);
+        button3.setLayerType(layerType, null);
+        button1a.setLayerType(layerType, null);
+        button2a.setLayerType(layerType, null);
+        button3a.setLayerType(layerType, null);
+        button1b.setLayerType(layerType, null);
+        button2b.setLayerType(layerType, null);
+        button3b.setLayerType(layerType, null);
+        button4.setLayerType(layerType, null);
+        button5.setLayerType(layerType, null);
+        button6.setLayerType(layerType, null);
+        button7.setLayerType(layerType, null);
+        button8.setLayerType(layerType, null);
+    }
+
+    private void startAnimator(View target) {
+        ObjectAnimator anim1b = ObjectAnimator.ofFloat(target, View.ALPHA, 0);
+        anim1b.setRepeatCount(ValueAnimator.INFINITE);
+        anim1b.setRepeatMode(ValueAnimator.REVERSE);
+        anim1b.setDuration(1000);
+        anim1b.start();
+    }
+
+    public static class MyLayout extends LinearLayout {
+
+        public MyLayout(Context context) {
+            super(context);
+            setStaticTransformationsEnabled(true);
+        }
+
+        public MyLayout(Context context, AttributeSet attrs) {
+            super(context, attrs);
+            setStaticTransformationsEnabled(true);
+        }
+
+        public MyLayout(Context context, AttributeSet attrs, int defStyle) {
+            super(context, attrs, defStyle);
+            setStaticTransformationsEnabled(true);
+        }
+
+        @Override
+        protected boolean getChildStaticTransformation(View child, Transformation t) {
+            t.clear();
+            t.setAlpha(.35f);
+
+            return true;
+        }
+    }
+}
+
diff --git a/tests/RenderScriptTests/SurfaceTexture/Android.mk b/tests/RenderScriptTests/SurfaceTexture/Android.mk
new file mode 100644
index 0000000..bbd4d55
--- /dev/null
+++ b/tests/RenderScriptTests/SurfaceTexture/Android.mk
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2012 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)
+
+# TODO: build fails with this set
+# LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := RsSurfaceTextureOpaque
+
+include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/SurfaceTexture/AndroidManifest.xml b/tests/RenderScriptTests/SurfaceTexture/AndroidManifest.xml
new file mode 100644
index 0000000..8aaa239
--- /dev/null
+++ b/tests/RenderScriptTests/SurfaceTexture/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.rs.sto">
+    <uses-sdk android:minSdkVersion="14" />
+    <uses-permission android:name="android.permission.CAMERA" />
+    <uses-feature android:name="android.hardware.camera" />
+    <uses-feature android:name="android.hardware.camera.autofocus" />
+
+    <application
+        android:label="RsSurfaceTextureOpaque"
+        android:hardwareAccelerated="true"
+        android:icon="@drawable/test_pattern">
+
+        <activity android:name="SurfaceTextureOpaque">
+            <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/SurfaceTexture/res/drawable/test_pattern.png b/tests/RenderScriptTests/SurfaceTexture/res/drawable/test_pattern.png
new file mode 100644
index 0000000..e7d1455
--- /dev/null
+++ b/tests/RenderScriptTests/SurfaceTexture/res/drawable/test_pattern.png
Binary files differ
diff --git a/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/CameraCapture.java b/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/CameraCapture.java
new file mode 100644
index 0000000..afdab41
--- /dev/null
+++ b/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/CameraCapture.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2012 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.sto;
+
+import android.graphics.SurfaceTexture;
+import android.hardware.Camera;
+import android.os.SystemClock;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.List;
+
+public class CameraCapture {
+
+    public interface CameraFrameListener {
+        public void onNewCameraFrame();
+    }
+
+    static final int FRAMES_PER_SEC = 30;
+
+    private Camera mCamera;
+    private SurfaceTexture mSurfaceTexture;
+
+    private int mProgram;
+
+    private int mCameraTransformHandle;
+    private int mTexSamplerHandle;
+    private int mTexCoordHandle;
+    private int mPosCoordHandle;
+
+    private float[] mCameraTransform = new float[16];
+
+    private int mCameraId = 0;
+    private int mWidth;
+    private int mHeight;
+
+    private long mStartCaptureTime = 0;
+
+    private boolean mNewFrameAvailable = false;
+    private boolean mIsOpen = false;
+
+    private CameraFrameListener mListener;
+
+    public synchronized void beginCapture(int cameraId, int width, int height,
+                                          SurfaceTexture st) {
+        mCameraId = cameraId;
+        mSurfaceTexture = st;
+
+        // Open the camera
+        openCamera(width, height);
+
+        // Start the camera
+        mStartCaptureTime = SystemClock.elapsedRealtime();
+        mCamera.startPreview();
+        mIsOpen = true;
+    }
+
+    public void getCurrentFrame() {
+        if (checkNewFrame()) {
+            if (mStartCaptureTime > 0 && SystemClock.elapsedRealtime() - mStartCaptureTime > 2000) {
+                // Lock white-balance and exposure for effects
+                Log.i("CC", "Locking white-balance and exposure!");
+                Camera.Parameters params = mCamera.getParameters();
+                params.setAutoWhiteBalanceLock(true);
+                params.setAutoExposureLock(true);
+                //mCamera.setParameters(params);
+                mStartCaptureTime = 0;
+            }
+
+            mSurfaceTexture.updateTexImage();
+            mSurfaceTexture.getTransformMatrix(mCameraTransform);
+
+            // display it here
+        }
+    }
+
+    public synchronized boolean hasNewFrame() {
+        return mNewFrameAvailable;
+    }
+
+    public synchronized void endCapture() {
+        mIsOpen = false;
+        if (mCamera != null) {
+            mCamera.release();
+            mCamera = null;
+            mSurfaceTexture = null;
+        }
+    }
+
+    public synchronized boolean isOpen() {
+        return mIsOpen;
+    }
+
+    public int getWidth() {
+        return mWidth;
+    }
+
+    public int getHeight() {
+        return mHeight;
+    }
+
+    public void setCameraFrameListener(CameraFrameListener listener) {
+        mListener = listener;
+    }
+
+    private void openCamera(int width, int height) {
+        // Setup camera
+        mCamera = Camera.open(mCameraId);
+        mCamera.setParameters(calcCameraParameters(width, height));
+
+        // Create camera surface texture
+        try {
+            mCamera.setPreviewTexture(mSurfaceTexture);
+        } catch (IOException e) {
+            throw new RuntimeException("Could not bind camera surface texture: " +
+                                       e.getMessage() + "!");
+        }
+
+        // Connect SurfaceTexture to callback
+        mSurfaceTexture.setOnFrameAvailableListener(onCameraFrameAvailableListener);
+    }
+
+    private Camera.Parameters calcCameraParameters(int width, int height) {
+        Camera.Parameters params = mCamera.getParameters();
+        params.setPreviewSize(mWidth, mHeight);
+
+        // Find closest size
+        int closestSize[] = findClosestSize(width, height, params);
+        mWidth = closestSize[0];
+        mHeight = closestSize[1];
+        params.setPreviewSize(mWidth, mHeight);
+
+        // Find closest FPS
+        int closestRange[] = findClosestFpsRange(FRAMES_PER_SEC, params);
+
+        params.setPreviewFpsRange(closestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
+                                  closestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
+
+        return params;
+    }
+
+    private int[] findClosestSize(int width, int height, Camera.Parameters parameters) {
+        List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
+        int closestWidth = -1;
+        int closestHeight = -1;
+        int smallestWidth = previewSizes.get(0).width;
+        int smallestHeight =  previewSizes.get(0).height;
+        for (Camera.Size size : previewSizes) {
+            // Best match defined as not being larger in either dimension than
+            // the requested size, but as close as possible. The below isn't a
+            // stable selection (reording the size list can give different
+            // results), but since this is a fallback nicety, that's acceptable.
+            if ( size.width <= width &&
+                 size.height <= height &&
+                 size.width >= closestWidth &&
+                 size.height >= closestHeight) {
+                closestWidth = size.width;
+                closestHeight = size.height;
+            }
+            if ( size.width < smallestWidth &&
+                 size.height < smallestHeight) {
+                smallestWidth = size.width;
+                smallestHeight = size.height;
+            }
+        }
+        if (closestWidth == -1) {
+            // Requested size is smaller than any listed size; match with smallest possible
+            closestWidth = smallestWidth;
+            closestHeight = smallestHeight;
+        }
+        int[] closestSize = {closestWidth, closestHeight};
+        return closestSize;
+    }
+
+    private int[] findClosestFpsRange(int fps, Camera.Parameters params) {
+        List<int[]> supportedFpsRanges = params.getSupportedPreviewFpsRange();
+        int[] closestRange = supportedFpsRanges.get(0);
+        int fpsk = fps * 1000;
+        int minDiff = 1000000;
+        for (int[] range : supportedFpsRanges) {
+            int low = range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX];
+            int high = range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX];
+            if (low <= fpsk && high >= fpsk) {
+                int diff = (fpsk - low) + (high - fpsk);
+                if (diff < minDiff) {
+                    closestRange = range;
+                    minDiff = diff;
+                }
+            }
+        }
+        Log.i("CC", "Found closest range: "
+            + closestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] + " - "
+            + closestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
+        return closestRange;
+    }
+
+    private synchronized void signalNewFrame() {
+        mNewFrameAvailable = true;
+        if (mListener != null) {
+            mListener.onNewCameraFrame();
+        }
+    }
+
+    private synchronized boolean checkNewFrame() {
+        if (mNewFrameAvailable) {
+            mNewFrameAvailable = false;
+            return true;
+        }
+        return false;
+    }
+
+    private SurfaceTexture.OnFrameAvailableListener onCameraFrameAvailableListener =
+            new SurfaceTexture.OnFrameAvailableListener() {
+        @Override
+        public void onFrameAvailable(SurfaceTexture surfaceTexture) {
+            signalNewFrame();
+        }
+    };
+}
diff --git a/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/SurfaceTextureOpaque.java b/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/SurfaceTextureOpaque.java
new file mode 100644
index 0000000..a51edaa
--- /dev/null
+++ b/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/SurfaceTextureOpaque.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2012 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.sto;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.provider.Settings.System;
+import android.util.Log;
+import android.view.View;
+import android.graphics.SurfaceTexture;
+
+import java.lang.Runtime;
+
+public class SurfaceTextureOpaque extends Activity {
+    private SurfaceTextureOpaqueView mView;
+    CameraCapture mCC;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mView = new SurfaceTextureOpaqueView(this);
+        setContentView(mView);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mView.resume();
+        startCamera();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        mView.pause();
+        mCC.endCapture();
+    }
+
+    cfl mCFL;
+    public void startCamera() {
+        mCC = new CameraCapture();
+        mCFL = new cfl();
+
+        mCC.setCameraFrameListener(mCFL);
+
+        mCC.beginCapture(1, 640, 480, mView.getST());
+    }
+
+    public class cfl implements CameraCapture.CameraFrameListener {
+        public void onNewCameraFrame() {
+            mView.mRender.newFrame();
+        }
+    }
+
+}
+
diff --git a/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/SurfaceTextureOpaqueRS.java b/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/SurfaceTextureOpaqueRS.java
new file mode 100644
index 0000000..b638b7d
--- /dev/null
+++ b/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/SurfaceTextureOpaqueRS.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2012 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.sto;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.graphics.SurfaceTexture;
+import android.util.Log;
+
+
+public class SurfaceTextureOpaqueRS {
+    static final private int NUM_CAMERA_PREVIEW_BUFFERS = 2;
+
+    public SurfaceTextureOpaqueRS() {
+    }
+
+    private Resources mRes;
+    private RenderScriptGL mRS;
+    private ScriptC_sto mScript;
+    private SurfaceTexture mST;
+    private Allocation mSto;
+    private Allocation mSto2;
+    private Allocation mRto;
+    private ProgramFragment mPF;
+
+    public void init(RenderScriptGL rs, Resources res) {
+        mRS = rs;
+        mRes = res;
+
+        Type.Builder tb = new Type.Builder(mRS, Element.RGBA_8888(mRS));
+        tb.setX(640);
+        tb.setY(480);
+        mSto = Allocation.createTyped(mRS, tb.create(), Allocation.USAGE_GRAPHICS_TEXTURE |
+                                                 Allocation.USAGE_IO_INPUT);
+        mRto = Allocation.createTyped(mRS, tb.create(), Allocation.USAGE_GRAPHICS_RENDER_TARGET |
+                                                 Allocation.USAGE_IO_OUTPUT);
+        mSto2 = Allocation.createTyped(mRS, tb.create(), Allocation.USAGE_GRAPHICS_TEXTURE |
+                                                 Allocation.USAGE_IO_INPUT);
+        mST = mSto.getSurfaceTexture();
+        mRto.setSurfaceTexture(mSto2.getSurfaceTexture());
+
+        ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs);
+        pfb.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
+                       ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
+        mPF = pfb.create();
+        mPF.bindSampler(Sampler.CLAMP_NEAREST(mRS), 0);
+        rs.bindProgramFragment(mPF);
+
+        mScript = new ScriptC_sto(mRS, mRes, R.raw.sto);
+        mScript.set_sto(mSto);
+        mScript.set_rto(mRto);
+        mScript.set_sto2(mSto2);
+        mScript.set_pf(mPF);
+
+        mRS.bindRootScript(mScript);
+
+
+        android.util.Log.v("sto", "Init complete");
+    }
+
+    SurfaceTexture getST() {
+        return mST;
+    }
+
+    public void newFrame() {
+        mSto.ioReceive();
+    }
+
+}
diff --git a/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/SurfaceTextureOpaqueView.java b/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/SurfaceTextureOpaqueView.java
new file mode 100644
index 0000000..f5e49f2
--- /dev/null
+++ b/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/SurfaceTextureOpaqueView.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2012 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.sto;
+
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScriptGL;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.SurfaceTexture;
+import android.util.Log;
+
+public class SurfaceTextureOpaqueView extends RSSurfaceView {
+
+    public SurfaceTextureOpaqueView(Context context) {
+        super(context);
+    }
+
+    RenderScriptGL mRS;
+    SurfaceTextureOpaqueRS mRender;
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        if (mRS != null) {
+            mRS = null;
+            destroyRenderScriptGL();
+        }
+    }
+
+    SurfaceTexture getST() {
+        RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+        mRS = createRenderScriptGL(sc);
+        mRender = new SurfaceTextureOpaqueRS();
+        mRender.init(mRS, getResources());
+        return mRender.getST();
+    }
+
+}
+
+
diff --git a/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/sto.rs b/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/sto.rs
new file mode 100644
index 0000000..efa901a
--- /dev/null
+++ b/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/sto.rs
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2012 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.sto)
+
+#pragma stateFragment(parent)
+
+#include "rs_graphics.rsh"
+
+
+rs_program_fragment pf;
+rs_allocation sto;  // camera in
+rs_allocation sto2;
+rs_allocation rto;  // render target
+
+int root() {
+    rsgBindTexture(pf, 0, sto);
+
+#if 1
+    rsgBindColorTarget(rto, 0);
+
+    rsgClearColor(0.f, 1.f, 0.f, 1.f);
+    rsgDrawQuadTexCoords(0, 0, 0, 0,0,
+                         0,500,0, 1,0,
+                         500,500,0, 1, 1,
+                         500, 0, 0, 0, 1 );
+    rsgClearColorTarget(0);
+
+    // io ops
+    rsAllocationIoSend(rto);
+    rsAllocationIoReceive(sto2);
+
+    rsgBindTexture(pf, 0, sto2);
+#endif
+
+    rsgClearColor(0.f, 1.f, 0.f, 1.f);
+    rsgDrawQuadTexCoords(0, 0, 0, 0,0,
+                         0,500,0, 1,0,
+                         500,500,0, 1, 1,
+                         500, 0, 0, 0, 1 );
+
+    return 1;
+}
+