Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e7bf1593 authored by Winson Chung's avatar Winson Chung
Browse files

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
parent 2db1dd81
Loading
Loading
Loading
Loading
+35 −4
Original line number Diff line number Diff line
@@ -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);
        }
    }
}