From e7bf15932baac168403af6e42ca57e1d008d9b84 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Tue, 9 Aug 2022 19:12:54 +0000 Subject: [PATCH] Force finish pending frame drawn callback once launcher is stopped - In rare cases, we may schedule to update the taskview with a screenshot but Launcher will not finish calling back because the activity is stopped (can be the result of the animation cancelling back to the app), which prevents Launcher from scheduling any frames and properly decrementing the frame count. Bug: 202776119 Test: Launch an app with sharesheet, swipe up and verify that screenshot callbacks Change-Id: I6b7e121fd5d9ef27ef5cccca060a4ff819fe9acc --- .../src/com/android/quickstep/ViewUtils.java | 39 +++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/quickstep/src/com/android/quickstep/ViewUtils.java b/quickstep/src/com/android/quickstep/ViewUtils.java index 1fef544e3e..1bb95b97f9 100644 --- a/quickstep/src/com/android/quickstep/ViewUtils.java +++ b/quickstep/src/com/android/quickstep/ViewUtils.java @@ -17,6 +17,7 @@ package com.android.quickstep; import android.graphics.HardwareRenderer; import android.os.Handler; +import android.view.SurfaceControl; import android.view.View; import android.view.ViewRootImpl; @@ -45,22 +46,42 @@ public class ViewUtils { 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 @@ public class ViewUtils { return; } - if (mFinishCallback != null) { - mFinishCallback.run(); - } + finish(); } private boolean schedule() { @@ -90,5 +109,17 @@ public class ViewUtils { } return false; } + + private void finish() { + if (mFinished) { + return; + } + mFinished = true; + mDeferFrameCount = 0; + if (mFinishCallback != null) { + mFinishCallback.run(); + } + mViewRoot.removeSurfaceChangedCallback(this); + } } }