OSDN Git Service

DO NOT MERGE Move SurfaceView offscreen if the app stops drawing it
authorJohn Reck <jreck@google.com>
Thu, 16 Jun 2016 22:36:13 +0000 (15:36 -0700)
committerJohn Reck <jreck@google.com>
Fri, 17 Jun 2016 20:26:10 +0000 (20:26 +0000)
Bug: 29360411
Change-Id: Iefb9d7a9dafb34a2b4f79130a2a8b5a7cf7de906
(cherry picked from commit aa6e84f21ddf89ea649a3f00044bc23adfe86978)

core/java/android/view/SurfaceView.java
core/jni/android_view_RenderNode.cpp
libs/hwui/RenderNode.cpp
libs/hwui/RenderNode.h

index d59c8ac..17834fb 100644 (file)
@@ -464,7 +464,8 @@ public class SurfaceView extends View {
             || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
             getLocationInWindow(mLocation);
 
-            if (DEBUG) Log.i(TAG, "Changes: creating=" + creating
+            if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+                    + "Changes: creating=" + creating
                     + " format=" + formatChanged + " size=" + sizeChanged
                     + " visible=" + visibleChanged
                     + " left=" + (mWindowSpaceLeft != mLocation[0])
@@ -534,7 +535,8 @@ public class SurfaceView extends View {
                     mReportDrawNeeded = false;
                     mDrawingStopped = !visible;
 
-                    if (DEBUG) Log.i(TAG, "Cur surface: " + mSurface);
+                    if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+                            + "Cur surface: " + mSurface);
 
                     relayoutResult = mSession.relayout(
                         mWindow, mWindow.mSeq, mLayout, mWindowSpaceWidth, mWindowSpaceHeight,
@@ -547,7 +549,8 @@ public class SurfaceView extends View {
                         reportDrawNeeded = true;
                     }
 
-                    if (DEBUG) Log.i(TAG, "New surface: " + mNewSurface
+                    if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+                            + "New surface: " + mNewSurface
                             + ", vis=" + visible + ", frame=" + mWinFrame);
 
                     mSurfaceFrame.left = 0;
@@ -581,7 +584,8 @@ public class SurfaceView extends View {
                     if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
                         mSurfaceCreated = false;
                         if (mSurface.isValid()) {
-                            if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceDestroyed");
+                            if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+                                    + "visibleChanged -- surfaceDestroyed");
                             callbacks = getSurfaceCallbacks();
                             for (SurfaceHolder.Callback c : callbacks) {
                                 c.surfaceDestroyed(mSurfaceHolder);
@@ -594,7 +598,8 @@ public class SurfaceView extends View {
                         if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
                             mSurfaceCreated = true;
                             mIsCreating = true;
-                            if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceCreated");
+                            if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+                                    + "visibleChanged -- surfaceCreated");
                             if (callbacks == null) {
                                 callbacks = getSurfaceCallbacks();
                             }
@@ -604,7 +609,8 @@ public class SurfaceView extends View {
                         }
                         if (creating || formatChanged || sizeChanged
                                 || visibleChanged || realSizeChanged) {
-                            if (DEBUG) Log.i(TAG, "surfaceChanged -- format=" + mFormat
+                            if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+                                    + "surfaceChanged -- format=" + mFormat
                                     + " w=" + myWidth + " h=" + myHeight);
                             if (callbacks == null) {
                                 callbacks = getSurfaceCallbacks();
@@ -614,7 +620,8 @@ public class SurfaceView extends View {
                             }
                         }
                         if (redrawNeeded) {
-                            if (DEBUG) Log.i(TAG, "surfaceRedrawNeeded");
+                            if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+                                    + "surfaceRedrawNeeded");
                             if (callbacks == null) {
                                 callbacks = getSurfaceCallbacks();
                             }
@@ -629,7 +636,8 @@ public class SurfaceView extends View {
                 } finally {
                     mIsCreating = false;
                     if (redrawNeeded) {
-                        if (DEBUG) Log.i(TAG, "finishedDrawing");
+                        if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+                                + "finishedDrawing");
                         mSession.finishDrawing(mWindow);
                     }
                     mSession.performDeferredDestroy(mWindow);
@@ -663,8 +671,9 @@ public class SurfaceView extends View {
                 }
 
                 try {
-                    Log.d(TAG, String.format("updateWindowPosition UI, " +
-                            "postion = [%d, %d, %d, %d]", mWinFrame.left, mWinFrame.top,
+                    Log.d(TAG, String.format("%d updateWindowPosition UI, " +
+                            "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
+                            mWinFrame.left, mWinFrame.top,
                             mWinFrame.right, mWinFrame.bottom));
                     mSession.repositionChild(mWindow, mWinFrame.left, mWinFrame.top,
                             mWinFrame.right, mWinFrame.bottom, -1, mWinFrame);
@@ -697,9 +706,9 @@ public class SurfaceView extends View {
         }
         try {
             if (DEBUG) {
-                Log.d(TAG, String.format("updateWindowPosition RT, frameNr = %d, " +
-                        "postion = [%d, %d, %d, %d]", frameNumber, left, top,
-                        right, bottom));
+                Log.d(TAG, String.format("%d updateWindowPosition RT, frameNr = %d, " +
+                        "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
+                        frameNumber, left, top, right, bottom));
             }
             // Just using mRTLastReportedPosition as a dummy rect here
             session.repositionChild(window, left, top, right, bottom,
@@ -712,6 +721,25 @@ public class SurfaceView extends View {
         }
     }
 
+    /**
+     * Called by native on RenderThread to notify that the window is no longer in the
+     * draw tree
+     * @hide
+     */
+    public final void windowPositionLostRT(long frameNumber) {
+        if (DEBUG) {
+            Log.d(TAG, String.format("%d windowPositionLostRT RT, frameNr = %d",
+                    System.identityHashCode(this), frameNumber));
+        }
+        // TODO: This is a bit of a hack as we don't have an API to report to WM
+        // to hide a window with a frameNumber, so just shift the window very far into
+        // negative space which will do effectively the same thing.
+        // Use the last reported size to avoid influencing the size of the bufferqueue
+        int x = -1000 - mRTLastReportedPosition.width();
+        int y = -1000 - mRTLastReportedPosition.height();
+        updateWindowPositionRT(frameNumber, x, y, -1000, -1000);
+    }
+
     private SurfaceHolder.Callback[] getSurfaceCallbacks() {
         SurfaceHolder.Callback callbacks[];
         synchronized (mCallbacks) {
@@ -750,8 +778,7 @@ public class SurfaceView extends View {
                 boolean alwaysConsumeNavBar) {
             SurfaceView surfaceView = mSurfaceView.get();
             if (surfaceView != null) {
-                if (DEBUG) Log.v(
-                        "SurfaceView", surfaceView + " got resized: w=" + frame.width()
+                if (DEBUG) Log.v(TAG, surfaceView + " got resized: w=" + frame.width()
                         + " h=" + frame.height() + ", cur w=" + mCurWidth + " h=" + mCurHeight);
                 surfaceView.mSurfaceLock.lock();
                 try {
@@ -907,7 +934,7 @@ public class SurfaceView extends View {
         private final Canvas internalLockCanvas(Rect dirty) {
             mSurfaceLock.lock();
 
-            if (DEBUG) Log.i(TAG, "Locking canvas... stopped="
+            if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
                     + mDrawingStopped + ", win=" + mWindow);
 
             Canvas c = null;
@@ -919,7 +946,7 @@ public class SurfaceView extends View {
                 }
             }
 
-            if (DEBUG) Log.i(TAG, "Returned canvas: " + c);
+            if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Returned canvas: " + c);
             if (c != null) {
                 mLastLockTime = SystemClock.uptimeMillis();
                 return c;
index a6db0f4..4fc546c 100644 (file)
@@ -534,6 +534,7 @@ static void android_view_RenderNode_endAllAnimators(JNIEnv* env, jobject clazz,
 // ----------------------------------------------------------------------------
 
 jmethodID gSurfaceViewPositionUpdateMethod;
+jmethodID gSurfaceViewPositionLostMethod;
 
 static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,
         jlong renderNodePtr, jobject surfaceview) {
@@ -581,6 +582,20 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,
             info.canvasContext.enqueueFrameWork(std::move(functor));
         }
 
+        virtual void onPositionLost(RenderNode& node, const TreeInfo* info) override {
+            if (CC_UNLIKELY(!mWeakRef || (info && !info->updateWindowPositions))) return;
+
+            if (info) {
+                auto functor = std::bind(
+                    std::mem_fn(&SurfaceViewPositionUpdater::doNotifyPositionLost), this,
+                    (jlong) info->canvasContext.getFrameNumber());
+
+                info->canvasContext.enqueueFrameWork(std::move(functor));
+            } else {
+                doNotifyPositionLost(0);
+            }
+        }
+
     private:
         JNIEnv* jnienv() {
             JNIEnv* env;
@@ -607,6 +622,21 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,
             env->DeleteLocalRef(localref);
         }
 
+        void doNotifyPositionLost(jlong frameNumber) {
+            ATRACE_NAME("SurfaceView position lost");
+
+            JNIEnv* env = jnienv();
+            jobject localref = env->NewLocalRef(mWeakRef);
+            if (CC_UNLIKELY(!localref)) {
+                jnienv()->DeleteWeakGlobalRef(mWeakRef);
+                mWeakRef = nullptr;
+                return;
+            }
+
+            env->CallVoidMethod(localref, gSurfaceViewPositionLostMethod, frameNumber);
+            env->DeleteLocalRef(localref);
+        }
+
         JavaVM* mVm;
         jobject mWeakRef;
     };
@@ -701,6 +731,8 @@ int register_android_view_RenderNode(JNIEnv* env) {
     jclass clazz = FindClassOrDie(env, "android/view/SurfaceView");
     gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz,
             "updateWindowPositionRT", "(JIIII)V");
+    gSurfaceViewPositionLostMethod = GetMethodIDOrDie(env, clazz,
+            "windowPositionLostRT", "(J)V");
     clazz = FindClassOrDie(env, "android/view/RenderNode");
     gOnRenderNodeDetached = GetMethodIDOrDie(env, clazz,
             "onRenderNodeDetached", "()V");
index be2dab9..d48d544 100644 (file)
@@ -464,7 +464,7 @@ void RenderNode::applyLayerPropertiesToLayer(TreeInfo& info) {
 }
 #endif
 
-void RenderNode::syncDisplayList(TreeObserver* observer) {
+void RenderNode::syncDisplayList(TreeInfo* info) {
     // Make sure we inc first so that we don't fluctuate between 0 and 1,
     // which would thrash the layer cache
     if (mStagingDisplayList) {
@@ -472,7 +472,7 @@ void RenderNode::syncDisplayList(TreeObserver* observer) {
             child->renderNode->incParentRefCount();
         }
     }
-    deleteDisplayList(observer);
+    deleteDisplayList(info ? info->observer : nullptr, info);
     mDisplayList = mStagingDisplayList;
     mStagingDisplayList = nullptr;
     if (mDisplayList) {
@@ -491,15 +491,15 @@ void RenderNode::pushStagingDisplayListChanges(TreeInfo& info) {
         // Damage with the old display list first then the new one to catch any
         // changes in isRenderable or, in the future, bounds
         damageSelf(info);
-        syncDisplayList(info.observer);
+        syncDisplayList(&info);
         damageSelf(info);
     }
 }
 
-void RenderNode::deleteDisplayList(TreeObserver* observer) {
+void RenderNode::deleteDisplayList(TreeObserver* observer, TreeInfo* info) {
     if (mDisplayList) {
         for (auto&& child : mDisplayList->getChildren()) {
-            child->renderNode->decParentRefCount(observer);
+            child->renderNode->decParentRefCount(observer, info);
         }
     }
     delete mDisplayList;
@@ -531,35 +531,38 @@ void RenderNode::prepareSubTree(TreeInfo& info, bool functorsNeedLayer, DisplayL
     }
 }
 
-void RenderNode::destroyHardwareResources(TreeObserver* observer) {
+void RenderNode::destroyHardwareResources(TreeObserver* observer, TreeInfo* info) {
     if (mLayer) {
         destroyLayer(mLayer);
         mLayer = nullptr;
     }
     if (mDisplayList) {
         for (auto&& child : mDisplayList->getChildren()) {
-            child->renderNode->destroyHardwareResources(observer);
+            child->renderNode->destroyHardwareResources(observer, info);
         }
         if (mNeedsDisplayListSync) {
             // Next prepare tree we are going to push a new display list, so we can
             // drop our current one now
-            deleteDisplayList(observer);
+            deleteDisplayList(observer, info);
         }
     }
 }
 
-void RenderNode::decParentRefCount(TreeObserver* observer) {
+void RenderNode::decParentRefCount(TreeObserver* observer, TreeInfo* info) {
     LOG_ALWAYS_FATAL_IF(!mParentCount, "already 0!");
     mParentCount--;
     if (!mParentCount) {
         if (observer) {
             observer->onMaybeRemovedFromTree(this);
         }
+        if (CC_UNLIKELY(mPositionListener.get())) {
+            mPositionListener->onPositionLost(*this, info);
+        }
         // If a child of ours is being attached to our parent then this will incorrectly
         // destroy its hardware resources. However, this situation is highly unlikely
         // and the failure is "just" that the layer is re-created, so this should
         // be safe enough
-        destroyHardwareResources(observer);
+        destroyHardwareResources(observer, info);
     }
 }
 
index acdc3d8..f80be5e 100644 (file)
@@ -196,7 +196,7 @@ public:
     }
 
     ANDROID_API virtual void prepareTree(TreeInfo& info);
-    void destroyHardwareResources(TreeObserver* observer);
+    void destroyHardwareResources(TreeObserver* observer, TreeInfo* info = nullptr);
 
     // UI thread only!
     ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
@@ -228,10 +228,19 @@ public:
     OffscreenBuffer** getLayerHandle() { return &mLayer; } // ugh...
 #endif
 
+    // Note: The position callbacks are relying on the listener using
+    // the frameNumber to appropriately batch/synchronize these transactions.
+    // There is no other filtering/batching to ensure that only the "final"
+    // state called once per frame.
     class ANDROID_API PositionListener {
     public:
         virtual ~PositionListener() {}
+        // Called when the RenderNode's position changes
         virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) = 0;
+        // Called when the RenderNode no longer has a position. As in, it's
+        // no longer being drawn.
+        // Note, tree info might be null
+        virtual void onPositionLost(RenderNode& node, const TreeInfo* info) = 0;
     };
 
     // Note this is not thread safe, this needs to be called
@@ -306,7 +315,7 @@ private:
 
 
     void syncProperties();
-    void syncDisplayList(TreeObserver* observer);
+    void syncDisplayList(TreeInfo* info);
 
     void prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer);
     void pushStagingPropertiesChanges(TreeInfo& info);
@@ -317,11 +326,11 @@ private:
 #endif
     void prepareLayer(TreeInfo& info, uint32_t dirtyMask);
     void pushLayerUpdate(TreeInfo& info);
-    void deleteDisplayList(TreeObserver* observer);
+    void deleteDisplayList(TreeObserver* observer, TreeInfo* info = nullptr);
     void damageSelf(TreeInfo& info);
 
     void incParentRefCount() { mParentCount++; }
-    void decParentRefCount(TreeObserver* observer);
+    void decParentRefCount(TreeObserver* observer, TreeInfo* info = nullptr);
 
     String8 mName;
     sp<VirtualLightRefBase> mUserContext;