Merge "Force finish pending frame drawn callback once launcher is stopped" into tm-qpr-dev
diff --git a/quickstep/src/com/android/quickstep/ViewUtils.java b/quickstep/src/com/android/quickstep/ViewUtils.java
index 1fef544..1bb95b9 100644
--- a/quickstep/src/com/android/quickstep/ViewUtils.java
+++ b/quickstep/src/com/android/quickstep/ViewUtils.java
@@ -17,6 +17,7 @@
 
 import android.graphics.HardwareRenderer;
 import android.os.Handler;
+import android.view.SurfaceControl;
 import android.view.View;
 import android.view.ViewRootImpl;
 
@@ -45,23 +46,43 @@
         return new FrameHandler(view, onFinishRunnable, canceled).schedule();
     }
 
-    private static class FrameHandler implements HardwareRenderer.FrameDrawingCallback {
+    private static class FrameHandler implements HardwareRenderer.FrameDrawingCallback,
+            ViewRootImpl.SurfaceChangedCallback {
 
         final ViewRootImpl mViewRoot;
         final Runnable mFinishCallback;
         final BooleanSupplier mCancelled;
         final Handler mHandler;
+        boolean mFinished;
 
         int mDeferFrameCount = 1;
 
         FrameHandler(View view, Runnable finishCallback, BooleanSupplier cancelled) {
             mViewRoot = view.getViewRootImpl();
+            mViewRoot.addSurfaceChangedCallback(this);
             mFinishCallback = finishCallback;
             mCancelled = cancelled;
             mHandler = new Handler();
         }
 
         @Override
+        public void surfaceCreated(SurfaceControl.Transaction t) {
+            // Do nothing
+        }
+
+        @Override
+        public void surfaceReplaced(SurfaceControl.Transaction t) {
+            // Do nothing
+        }
+
+        @Override
+        public void surfaceDestroyed() {
+            // If the root view is detached, then the app won't get any scheduled frames so we need
+            // to force-run any pending callbacks
+            finish();
+        }
+
+        @Override
         public void onFrameDraw(long frame) {
             Utilities.postAsyncCallback(mHandler, this::onFrame);
         }
@@ -77,9 +98,7 @@
                 return;
             }
 
-            if (mFinishCallback != null) {
-                mFinishCallback.run();
-            }
+            finish();
         }
 
         private boolean schedule() {
@@ -90,5 +109,17 @@
             }
             return false;
         }
+
+        private void finish() {
+            if (mFinished) {
+                return;
+            }
+            mFinished = true;
+            mDeferFrameCount = 0;
+            if (mFinishCallback != null) {
+                mFinishCallback.run();
+            }
+            mViewRoot.removeSurfaceChangedCallback(this);
+        }
     }
 }