Have RT drive window positioning

Bug: 22802885

Change-Id: I6beed5474d3a943b16e9097f7bd61ce3cbd37505
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 88bffb5..3122c0b 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -135,6 +135,9 @@
     private RenderNode(String name, View owningView) {
         mNativeRenderNode = nCreate(name);
         mOwningView = owningView;
+        if (mOwningView instanceof SurfaceView) {
+            nRequestPositionUpdates(mNativeRenderNode, (SurfaceView) mOwningView);
+        }
     }
 
     /**
@@ -854,6 +857,8 @@
     private static native void nOutput(long renderNode);
     private static native int nGetDebugSize(long renderNode);
 
+    private static native void nRequestPositionUpdates(long renderNode, SurfaceView callback);
+
     ///////////////////////////////////////////////////////////////////////////
     // Animations
     ///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 5b48e28..a296051 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -135,7 +135,7 @@
         }
     };
 
-    final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
+    private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
             = new ViewTreeObserver.OnScrollChangedListener() {
                     @Override
                     public void onScrollChanged() {
@@ -143,6 +143,17 @@
                     }
             };
 
+    private final ViewTreeObserver.OnPreDrawListener mDrawListener =
+            new ViewTreeObserver.OnPreDrawListener() {
+                @Override
+                public boolean onPreDraw() {
+                    // reposition ourselves where the surface is
+                    mHaveFrame = getWidth() > 0 && getHeight() > 0;
+                    updateWindow(false, false);
+                    return true;
+                }
+            };
+
     boolean mRequestedVisible = false;
     boolean mWindowVisibility = false;
     boolean mViewVisibility = false;
@@ -168,17 +179,9 @@
     boolean mUpdateWindowNeeded;
     boolean mReportDrawNeeded;
     private Translator mTranslator;
+    private int mWindowInsetLeft;
+    private int mWindowInsetTop;
 
-    private final ViewTreeObserver.OnPreDrawListener mDrawListener =
-            new ViewTreeObserver.OnPreDrawListener() {
-                @Override
-                public boolean onPreDraw() {
-                    // reposition ourselves where the surface is
-                    mHaveFrame = getWidth() > 0 && getHeight() > 0;
-                    updateWindow(false, false);
-                    return true;
-                }
-            };
     private boolean mGlobalListenersAdded;
 
     public SurfaceView(Context context) {
@@ -443,17 +446,17 @@
         int myHeight = mRequestedHeight;
         if (myHeight <= 0) myHeight = getHeight();
 
-        getLocationInWindow(mLocation);
         final boolean creating = mWindow == null;
         final boolean formatChanged = mFormat != mRequestedFormat;
         final boolean sizeChanged = mWindowSpaceWidth != myWidth || mWindowSpaceHeight != myHeight;
         final boolean visibleChanged = mVisible != mRequestedVisible;
         final boolean layoutSizeChanged = getWidth() != mLayout.width
                 || getHeight() != mLayout.height;
-        final boolean positionChanged = mWindowSpaceLeft != mLocation[0] || mWindowSpaceTop != mLocation[1];
 
         if (force || creating || formatChanged || sizeChanged || visibleChanged
             || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
+            getLocationInWindow(mLocation);
+
             if (DEBUG) Log.i(TAG, "Changes: creating=" + creating
                     + " format=" + formatChanged + " size=" + sizeChanged
                     + " visible=" + visibleChanged
@@ -643,27 +646,69 @@
                 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
                 " w=" + mLayout.width + " h=" + mLayout.height +
                 ", frame=" + mSurfaceFrame);
-        } else if (positionChanged || layoutSizeChanged) { // Only the position has changed
-            mWindowSpaceLeft = mLocation[0];
-            mWindowSpaceTop = mLocation[1];
-            // For our size changed check, we keep mLayout.width and mLayout.height
-            // in view local space.
-            mLocation[0] = mLayout.width = getWidth();
-            mLocation[1] = mLayout.height = getHeight();
+        } else if (!isHardwareAccelerated()) {
+            getLocationInWindow(mLocation);
+            final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
+                    || mWindowSpaceTop != mLocation[1];
+            if (positionChanged || layoutSizeChanged) { // Only the position has changed
+                mWindowSpaceLeft = mLocation[0];
+                mWindowSpaceTop = mLocation[1];
+                // For our size changed check, we keep mLayout.width and mLayout.height
+                // in view local space.
+                mLocation[0] = mLayout.width = getWidth();
+                mLocation[1] = mLayout.height = getHeight();
 
-            transformFromViewToWindowSpace(mLocation);
+                transformFromViewToWindowSpace(mLocation);
 
-            try {
-                mSession.repositionChild(mWindow, mWindowSpaceLeft, mWindowSpaceTop,
-                        mLocation[0], mLocation[1],
-                        viewRoot != null ? viewRoot.getNextFrameNumber() : -1,
-                        mWinFrame);
-            } catch (RemoteException ex) {
-                Log.e(TAG, "Exception from relayout", ex);
+                try {
+                    Log.d(TAG, String.format("updateWindowPosition UI, " +
+                            "postion = [%d, %d, %d, %d]", mWindowSpaceLeft, mWindowSpaceTop,
+                            mLocation[0], mLocation[1]));
+                    mSession.repositionChild(mWindow, mWindowSpaceLeft, mWindowSpaceTop,
+                            mLocation[0], mLocation[1], -1, mWinFrame);
+                } catch (RemoteException ex) {
+                    Log.e(TAG, "Exception from relayout", ex);
+                }
             }
         }
     }
 
+    private Rect mRTLastReportedPosition = new Rect();
+
+    /**
+     * Called by native on RenderThread to update the window position
+     * @hide
+     */
+    public final void updateWindowPositionRT(long frameNumber,
+            int left, int top, int right, int bottom) {
+        IWindowSession session = mSession;
+        MyWindow window = mWindow;
+        if (session == null || window == null) {
+            // Guess we got detached, that sucks
+            return;
+        }
+        if (mRTLastReportedPosition.left == left
+                && mRTLastReportedPosition.top == top
+                && mRTLastReportedPosition.right == right
+                && mRTLastReportedPosition.bottom == bottom) {
+            return;
+        }
+        try {
+            if (DEBUG) {
+                Log.d(TAG, String.format("updateWindowPosition RT, frameNr = %d, " +
+                        "postion = [%d, %d, %d, %d]", frameNumber, left, top,
+                        right, bottom));
+            }
+            // Just using mRTLastReportedPosition as a dummy rect here
+            session.repositionChild(window, left, top, right, bottom, frameNumber,
+                    mRTLastReportedPosition);
+            // Now overwrite mRTLastReportedPosition with our values
+            mRTLastReportedPosition.set(left, top, right, bottom);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Exception from repositionChild", ex);
+        }
+    }
+
     private SurfaceHolder.Callback[] getSurfaceCallbacks() {
         SurfaceHolder.Callback callbacks[];
         synchronized (mCallbacks) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 98e3289..97e0143 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -6815,20 +6815,6 @@
         }
     }
 
-    long getNextFrameNumber() {
-        long frameNumber = -1;
-        if (mSurfaceHolder != null) {
-            mSurfaceHolder.mSurfaceLock.lock();
-        }
-        if (mSurface.isValid()) {
-            frameNumber =  mSurface.getNextFrameNumber();
-        }
-        if (mSurfaceHolder != null) {
-            mSurfaceHolder.mSurfaceLock.unlock();
-        }
-        return frameNumber;
-    }
-
     class TakenSurfaceHolder extends BaseSurfaceHolder {
         @Override
         public boolean onAllowLockCanvas() {
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index b1d4e26..a9003c1 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -15,6 +15,7 @@
  */
 
 #define LOG_TAG "OpenGLRenderer"
+#define ATRACE_TAG ATRACE_TAG_VIEW
 
 #include <EGL/egl.h>
 
@@ -24,7 +25,10 @@
 #include <android_runtime/AndroidRuntime.h>
 
 #include <Animator.h>
+#include <DamageAccumulator.h>
+#include <Matrix.h>
 #include <RenderNode.h>
+#include <TreeInfo.h>
 #include <Paint.h>
 
 #include "core_jni_helpers.h"
@@ -462,6 +466,69 @@
 }
 
 // ----------------------------------------------------------------------------
+// SurfaceView position callback
+// ----------------------------------------------------------------------------
+
+jmethodID gSurfaceViewPositionUpdateMethod;
+
+static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,
+        jlong renderNodePtr, jobject surfaceview) {
+    class SurfaceViewPositionUpdater : public RenderNode::PositionListener {
+    public:
+        SurfaceViewPositionUpdater(JNIEnv* env, jobject surfaceview) {
+            env->GetJavaVM(&mVm);
+            mWeakRef = env->NewWeakGlobalRef(surfaceview);
+        }
+
+        virtual ~SurfaceViewPositionUpdater() {
+            jnienv()->DeleteWeakGlobalRef(mWeakRef);
+            mWeakRef = nullptr;
+        }
+
+        virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) override {
+            if (CC_UNLIKELY(!mWeakRef || !info.updateWindowPositions)) return;
+            ATRACE_NAME("Update SurfaceView position");
+
+            JNIEnv* env = jnienv();
+            jobject localref = env->NewLocalRef(mWeakRef);
+            if (CC_UNLIKELY(!localref)) {
+                jnienv()->DeleteWeakGlobalRef(mWeakRef);
+                mWeakRef = nullptr;
+                return;
+            }
+            Matrix4 transform;
+            info.damageAccumulator->computeCurrentTransform(&transform);
+            const RenderProperties& props = node.properties();
+            uirenderer::Rect bounds(props.getWidth(), props.getHeight());
+            transform.mapRect(bounds);
+            bounds.left -= info.windowInsetLeft;
+            bounds.right -= info.windowInsetLeft;
+            bounds.top -= info.windowInsetTop;
+            bounds.bottom -= info.windowInsetTop;
+            env->CallVoidMethod(localref, gSurfaceViewPositionUpdateMethod,
+                    (jlong) info.frameNumber, (jint) bounds.left, (jint) bounds.top,
+                    (jint) bounds.right, (jint) bounds.bottom);
+            env->DeleteLocalRef(localref);
+        }
+
+    private:
+        JNIEnv* jnienv() {
+            JNIEnv* env;
+            if (mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+                LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", mVm);
+            }
+            return env;
+        }
+
+        JavaVM* mVm;
+        jobject mWeakRef;
+    };
+
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->setPositionListener(new SurfaceViewPositionUpdater(env, surfaceview));
+}
+
+// ----------------------------------------------------------------------------
 // JNI Glue
 // ----------------------------------------------------------------------------
 
@@ -539,9 +606,14 @@
 
     { "nAddAnimator",              "(JJ)V", (void*) android_view_RenderNode_addAnimator },
     { "nEndAllAnimators",          "(J)V", (void*) android_view_RenderNode_endAllAnimators },
+
+    { "nRequestPositionUpdates",   "(JLandroid/view/SurfaceView;)V", (void*) android_view_RenderNode_requestPositionUpdates },
 };
 
 int register_android_view_RenderNode(JNIEnv* env) {
+    jclass clazz = FindClassOrDie(env, "android/view/SurfaceView");
+    gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz,
+            "updateWindowPositionRT", "(JIIII)V");
     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index edced56..506395b 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -133,7 +133,14 @@
 
     virtual void prepareTree(TreeInfo& info) {
         info.errorHandler = this;
+        // TODO: This is hacky
+        info.windowInsetLeft = -stagingProperties().getLeft();
+        info.windowInsetTop = -stagingProperties().getTop();
+        info.updateWindowPositions = true;
         RenderNode::prepareTree(info);
+        info.updateWindowPositions = false;
+        info.windowInsetLeft = 0;
+        info.windowInsetTop = 0;
         info.errorHandler = NULL;
     }
 
@@ -368,28 +375,28 @@
 static void android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jobject jsurface) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    sp<ANativeWindow> window = android_view_Surface_getNativeWindow(env, jsurface);
-    proxy->initialize(window);
+    sp<Surface> surface = android_view_Surface_getSurface(env, jsurface);
+    proxy->initialize(surface);
 }
 
 static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jobject jsurface) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    sp<ANativeWindow> window;
+    sp<Surface> surface;
     if (jsurface) {
-        window = android_view_Surface_getNativeWindow(env, jsurface);
+        surface = android_view_Surface_getSurface(env, jsurface);
     }
-    proxy->updateSurface(window);
+    proxy->updateSurface(surface);
 }
 
 static jboolean android_view_ThreadedRenderer_pauseSurface(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jobject jsurface) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    sp<ANativeWindow> window;
+    sp<Surface> surface;
     if (jsurface) {
-        window = android_view_Surface_getNativeWindow(env, jsurface);
+        surface = android_view_Surface_getSurface(env, jsurface);
     }
-    return proxy->pauseSurface(window);
+    return proxy->pauseSurface(surface);
 }
 
 static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr,
diff --git a/libs/hwui/DamageAccumulator.h b/libs/hwui/DamageAccumulator.h
index e44fc20..250296e 100644
--- a/libs/hwui/DamageAccumulator.h
+++ b/libs/hwui/DamageAccumulator.h
@@ -57,7 +57,7 @@
     // Returns the current dirty area, *NOT* transformed by pushed transforms
     void peekAtDirty(SkRect* dest) const;
 
-    void computeCurrentTransform(Matrix4* outMatrix) const;
+    ANDROID_API void computeCurrentTransform(Matrix4* outMatrix) const;
 
     void finish(SkRect* totalDirty);
 
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index d4588ed..bade216 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -381,6 +381,10 @@
     bool childFunctorsNeedLayer = mProperties.prepareForFunctorPresence(
             willHaveFunctor, functorsNeedLayer);
 
+    if (CC_UNLIKELY(mPositionListener.get())) {
+        mPositionListener->onPositionUpdated(*this, info);
+    }
+
     prepareLayer(info, animatorDirtyMask);
     if (info.mode == TreeInfo::MODE_FULL) {
         pushStagingDisplayListChanges(info);
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 8e4a3df..f248de54 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -209,6 +209,19 @@
     OffscreenBuffer** getLayerHandle() { return &mLayer; } // ugh...
 #endif
 
+    class ANDROID_API PositionListener {
+    public:
+        virtual ~PositionListener() {}
+        virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) = 0;
+    };
+
+    // Note this is not thread safe, this needs to be called
+    // before the RenderNode is used for drawing.
+    // RenderNode takes ownership of the pointer
+    ANDROID_API void setPositionListener(PositionListener* listener) {
+        mPositionListener.reset(listener);
+    }
+
 private:
     typedef key_value_pair_t<float, DrawRenderNodeOp*> ZDrawRenderNodeOpPair;
 
@@ -317,6 +330,8 @@
     // This is *NOT* thread-safe, and should therefore only be tracking
     // mDisplayList, not mStagingDisplayList.
     uint32_t mParentCount;
+
+    std::unique_ptr<PositionListener> mPositionListener;
 }; // class RenderNode
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index be25516..accd303 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -86,6 +86,12 @@
 #endif
     ErrorHandler* errorHandler = nullptr;
 
+    // Frame number for use with synchronized surfaceview position updating
+    int64_t frameNumber = -1;
+    int32_t windowInsetLeft = 0;
+    int32_t windowInsetTop = 0;
+    bool updateWindowPositions = false;
+
     struct Out {
         bool hasFunctors = false;
         // This is only updated if evaluateAnimations is true
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index e7cf3ec..8207bdb 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -96,18 +96,18 @@
     }
 }
 
-void CanvasContext::setSurface(ANativeWindow* window) {
+void CanvasContext::setSurface(Surface* surface) {
     ATRACE_CALL();
 
-    mNativeWindow = window;
+    mNativeSurface = surface;
 
     if (mEglSurface != EGL_NO_SURFACE) {
         mEglManager.destroySurface(mEglSurface);
         mEglSurface = EGL_NO_SURFACE;
     }
 
-    if (window) {
-        mEglSurface = mEglManager.createSurface(window);
+    if (surface) {
+        mEglSurface = mEglManager.createSurface(surface);
     }
 
     if (mEglSurface != EGL_NO_SURFACE) {
@@ -131,8 +131,8 @@
     mSwapBehavior = swapBehavior;
 }
 
-void CanvasContext::initialize(ANativeWindow* window) {
-    setSurface(window);
+void CanvasContext::initialize(Surface* surface) {
+    setSurface(surface);
 #if !HWUI_NEW_OPS
     if (mCanvas) return;
     mCanvas = new OpenGLRenderer(mRenderThread.renderState());
@@ -140,11 +140,11 @@
 #endif
 }
 
-void CanvasContext::updateSurface(ANativeWindow* window) {
-    setSurface(window);
+void CanvasContext::updateSurface(Surface* surface) {
+    setSurface(surface);
 }
 
-bool CanvasContext::pauseSurface(ANativeWindow* window) {
+bool CanvasContext::pauseSurface(Surface* surface) {
     return mRenderThread.removeFrameCallback(this);
 }
 
@@ -208,6 +208,10 @@
     info.renderer = mCanvas;
 #endif
 
+    if (CC_LIKELY(mNativeSurface.get())) {
+        info.frameNumber = static_cast<int64_t>(mNativeSurface->getNextFrameNumber());
+    }
+
     mAnimationContext->startFrame(info.mode);
     for (const sp<RenderNode>& node : mRenderNodes) {
         // Only the primary target node will be drawn full - all other nodes would get drawn in
@@ -223,7 +227,7 @@
     freePrefetechedLayers();
     GL_CHECKPOINT(MODERATE);
 
-    if (CC_UNLIKELY(!mNativeWindow.get())) {
+    if (CC_UNLIKELY(!mNativeSurface.get())) {
         mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
         info.out.canDrawThisFrame = false;
         return;
@@ -246,8 +250,9 @@
         } else {
             // We're maybe behind? Find out for sure
             int runningBehind = 0;
-            mNativeWindow->query(mNativeWindow.get(),
-                    NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &runningBehind);
+            // TODO: Have this method be on Surface, too, not just ANativeWindow...
+            ANativeWindow* window = mNativeSurface.get();
+            window->query(window, NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &runningBehind);
             info.out.canDrawThisFrame = !runningBehind;
         }
     } else {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 270fb1f..00830e4 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -38,6 +38,7 @@
 #include <SkBitmap.h>
 #include <SkRect.h>
 #include <utils/Functor.h>
+#include <gui/Surface.h>
 
 #include <set>
 #include <string>
@@ -74,10 +75,10 @@
     // Won't take effect until next EGLSurface creation
     void setSwapBehavior(SwapBehavior swapBehavior);
 
-    void initialize(ANativeWindow* window);
-    void updateSurface(ANativeWindow* window);
-    bool pauseSurface(ANativeWindow* window);
-    bool hasSurface() { return mNativeWindow.get(); }
+    void initialize(Surface* surface);
+    void updateSurface(Surface* surface);
+    bool pauseSurface(Surface* surface);
+    bool hasSurface() { return mNativeSurface.get(); }
 
     void setup(int width, int height, float lightRadius,
             uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
@@ -171,7 +172,7 @@
     // lifecycle tracking
     friend class android::uirenderer::RenderState;
 
-    void setSurface(ANativeWindow* window);
+    void setSurface(Surface* window);
     void requireSurface();
 
     void freePrefetechedLayers();
@@ -181,7 +182,7 @@
 
     RenderThread& mRenderThread;
     EglManager& mEglManager;
-    sp<ANativeWindow> mNativeWindow;
+    sp<Surface> mNativeSurface;
     EGLSurface mEglSurface = EGL_NO_SURFACE;
     bool mBufferPreserved = false;
     SwapBehavior mSwapBehavior = kSwap_default;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 1d1b144..7c6cd7e 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -139,38 +139,38 @@
     postAndWait(task); // block since name/value pointers owned by caller
 }
 
-CREATE_BRIDGE2(initialize, CanvasContext* context, ANativeWindow* window) {
-    args->context->initialize(args->window);
+CREATE_BRIDGE2(initialize, CanvasContext* context, Surface* surface) {
+    args->context->initialize(args->surface);
     return nullptr;
 }
 
-void RenderProxy::initialize(const sp<ANativeWindow>& window) {
+void RenderProxy::initialize(const sp<Surface>& surface) {
     SETUP_TASK(initialize);
     args->context = mContext;
-    args->window = window.get();
+    args->surface = surface.get();
     post(task);
 }
 
-CREATE_BRIDGE2(updateSurface, CanvasContext* context, ANativeWindow* window) {
-    args->context->updateSurface(args->window);
+CREATE_BRIDGE2(updateSurface, CanvasContext* context, Surface* surface) {
+    args->context->updateSurface(args->surface);
     return nullptr;
 }
 
-void RenderProxy::updateSurface(const sp<ANativeWindow>& window) {
+void RenderProxy::updateSurface(const sp<Surface>& surface) {
     SETUP_TASK(updateSurface);
     args->context = mContext;
-    args->window = window.get();
+    args->surface = surface.get();
     postAndWait(task);
 }
 
-CREATE_BRIDGE2(pauseSurface, CanvasContext* context, ANativeWindow* window) {
-    return (void*) args->context->pauseSurface(args->window);
+CREATE_BRIDGE2(pauseSurface, CanvasContext* context, Surface* surface) {
+    return (void*) args->context->pauseSurface(args->surface);
 }
 
-bool RenderProxy::pauseSurface(const sp<ANativeWindow>& window) {
+bool RenderProxy::pauseSurface(const sp<Surface>& surface) {
     SETUP_TASK(pauseSurface);
     args->context = mContext;
-    args->window = window.get();
+    args->surface = surface.get();
     return (bool) postAndWait(task);
 }
 
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 4180d802..178724a 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -67,9 +67,9 @@
     ANDROID_API bool loadSystemProperties();
     ANDROID_API void setName(const char* name);
 
-    ANDROID_API void initialize(const sp<ANativeWindow>& window);
-    ANDROID_API void updateSurface(const sp<ANativeWindow>& window);
-    ANDROID_API bool pauseSurface(const sp<ANativeWindow>& window);
+    ANDROID_API void initialize(const sp<Surface>& surface);
+    ANDROID_API void updateSurface(const sp<Surface>& surface);
+    ANDROID_API bool pauseSurface(const sp<Surface>& surface);
     ANDROID_API void setup(int width, int height, float lightRadius,
             uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
     ANDROID_API void setLightCenter(const Vector3& lightCenter);
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index b028ce6..de7b9c2 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -356,6 +356,15 @@
         </activity>
 
         <activity
+                android:name="MovingSurfaceViewActivity"
+                android:label="SurfaceView/Animated Movement">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.hwui.TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity
                 android:name="GLTextureViewActivity"
                 android:label="TextureView/OpenGL">
             <intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MovingSurfaceViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/MovingSurfaceViewActivity.java
new file mode 100644
index 0000000..cd15ef1
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/MovingSurfaceViewActivity.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2016 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.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.SurfaceHolder;
+import android.view.SurfaceHolder.Callback;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.animation.LinearInterpolator;
+import android.widget.FrameLayout;
+
+public class MovingSurfaceViewActivity extends Activity implements Callback {
+    static final String TAG = "MovingSurfaceView";
+    SurfaceView mSurfaceView;
+    ObjectAnimator mAnimator;
+
+    class MySurfaceView extends SurfaceView {
+        boolean mSlowToggled;
+
+        public MySurfaceView(Context context) {
+            super(context);
+            setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    mSlowToggled = !mSlowToggled;
+                    Log.d(TAG, "SLOW MODE: " + mSlowToggled);
+                    invalidate();
+                }
+            });
+            setWillNotDraw(false);
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            super.draw(canvas);
+            if (mSlowToggled) {
+                try {
+                    Thread.sleep(16);
+                } catch (InterruptedException e) {}
+            }
+        }
+
+        public void setMyTranslationY(float ty) {
+            setTranslationY(ty);
+            if (mSlowToggled) {
+                invalidate();
+            }
+        }
+
+        public float getMyTranslationY() {
+            return getTranslationY();
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        FrameLayout content = new FrameLayout(this);
+
+        mSurfaceView = new MySurfaceView(this);
+        mSurfaceView.getHolder().addCallback(this);
+
+        final float density = getResources().getDisplayMetrics().density;
+        int size = (int) (200 * density);
+
+        content.addView(mSurfaceView, new FrameLayout.LayoutParams(
+                size, size, Gravity.CENTER));
+        mAnimator = ObjectAnimator.ofFloat(mSurfaceView, "myTranslationY",
+                0, size);
+        mAnimator.setRepeatMode(ObjectAnimator.REVERSE);
+        mAnimator.setRepeatCount(ObjectAnimator.INFINITE);
+        mAnimator.setDuration(200);
+        mAnimator.setInterpolator(new LinearInterpolator());
+        setContentView(content);
+    }
+
+    @Override
+    public void surfaceCreated(SurfaceHolder holder) {
+    }
+
+    @Override
+    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+        Canvas canvas = holder.lockCanvas();
+        canvas.drawARGB(0xFF, 0x00, 0xFF, 0x00);
+        holder.unlockCanvasAndPost(canvas);
+    }
+
+    @Override
+    public void surfaceDestroyed(SurfaceHolder holder) {
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mAnimator.start();
+    }
+
+    @Override
+    protected void onPause() {
+        mAnimator.pause();
+        super.onPause();
+    }
+}