Merge "Use OnImageAvailableListener to wait for buffer" into sc-dev am: 008af7300c

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15411889

Change-Id: I3b1ba7a5c3b0c7ea7fe03c879bd59e8f4b7b4fd1
This commit is contained in:
Mark Renouf
2021-07-30 20:49:52 +00:00
committed by Automerger Merge Worker
2 changed files with 47 additions and 11 deletions

View File

@@ -45,9 +45,12 @@ import androidx.concurrent.futures.CallbackToFutureAdapter;
import androidx.concurrent.futures.CallbackToFutureAdapter.Completer; import androidx.concurrent.futures.CallbackToFutureAdapter.Completer;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.dagger.qualifiers.Background;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import java.util.concurrent.Executor;
import javax.inject.Inject; import javax.inject.Inject;
/** /**
@@ -63,6 +66,8 @@ public class ScrollCaptureClient {
private static final String TAG = LogConfig.logTag(ScrollCaptureClient.class); private static final String TAG = LogConfig.logTag(ScrollCaptureClient.class);
private final Executor mBgExecutor;
/** /**
* Represents the connection to a target window and provides a mechanism for requesting tiles. * Represents the connection to a target window and provides a mechanism for requesting tiles.
*/ */
@@ -155,8 +160,10 @@ public class ScrollCaptureClient {
private IBinder mHostWindowToken; private IBinder mHostWindowToken;
@Inject @Inject
public ScrollCaptureClient(@UiContext Context context, IWindowManager windowManagerService) { public ScrollCaptureClient(IWindowManager windowManagerService,
@Background Executor bgExecutor, @UiContext Context context) {
requireNonNull(context.getDisplay(), "context must be associated with a Display!"); requireNonNull(context.getDisplay(), "context must be associated with a Display!");
mBgExecutor = bgExecutor;
mWindowManagerService = windowManagerService; mWindowManagerService = windowManagerService;
} }
@@ -220,21 +227,25 @@ public class ScrollCaptureClient {
return ""; return "";
} }
SessionWrapper session = new SessionWrapper(connection, response.getWindowBounds(), SessionWrapper session = new SessionWrapper(connection, response.getWindowBounds(),
response.getBoundsInWindow(), maxPages); response.getBoundsInWindow(), maxPages, mBgExecutor);
session.start(completer); session.start(completer);
return "IScrollCaptureCallbacks#onCaptureStarted"; return "IScrollCaptureCallbacks#onCaptureStarted";
}); });
} }
private static class SessionWrapper extends IScrollCaptureCallbacks.Stub implements Session, private static class SessionWrapper extends IScrollCaptureCallbacks.Stub implements Session,
IBinder.DeathRecipient { IBinder.DeathRecipient, ImageReader.OnImageAvailableListener {
private IScrollCaptureConnection mConnection; private IScrollCaptureConnection mConnection;
private final Executor mBgExecutor;
private final Object mLock = new Object();
private ImageReader mReader; private ImageReader mReader;
private final int mTileHeight; private final int mTileHeight;
private final int mTileWidth; private final int mTileWidth;
private Rect mRequestRect; private Rect mRequestRect;
private Rect mCapturedArea;
private Image mCapturedImage;
private boolean mStarted; private boolean mStarted;
private final int mTargetHeight; private final int mTargetHeight;
@@ -247,7 +258,8 @@ public class ScrollCaptureClient {
private Completer<Void> mEndCompleter; private Completer<Void> mEndCompleter;
private SessionWrapper(IScrollCaptureConnection connection, Rect windowBounds, private SessionWrapper(IScrollCaptureConnection connection, Rect windowBounds,
Rect boundsInWindow, float maxPages) throws RemoteException { Rect boundsInWindow, float maxPages, Executor bgExecutor)
throws RemoteException {
mConnection = requireNonNull(connection); mConnection = requireNonNull(connection);
mConnection.asBinder().linkToDeath(SessionWrapper.this, 0); mConnection.asBinder().linkToDeath(SessionWrapper.this, 0);
mWindowBounds = requireNonNull(windowBounds); mWindowBounds = requireNonNull(windowBounds);
@@ -259,7 +271,7 @@ public class ScrollCaptureClient {
mTileWidth = mBoundsInWindow.width(); mTileWidth = mBoundsInWindow.width();
mTileHeight = pxPerTile / mBoundsInWindow.width(); mTileHeight = pxPerTile / mBoundsInWindow.width();
mTargetHeight = (int) (mBoundsInWindow.height() * maxPages); mTargetHeight = (int) (mBoundsInWindow.height() * maxPages);
mBgExecutor = bgExecutor;
if (DEBUG_SCROLL) { if (DEBUG_SCROLL) {
Log.d(TAG, "boundsInWindow: " + mBoundsInWindow); Log.d(TAG, "boundsInWindow: " + mBoundsInWindow);
Log.d(TAG, "tile size: " + mTileWidth + "x" + mTileHeight); Log.d(TAG, "tile size: " + mTileWidth + "x" + mTileHeight);
@@ -289,6 +301,7 @@ public class ScrollCaptureClient {
mReader = ImageReader.newInstance(mTileWidth, mTileHeight, PixelFormat.RGBA_8888, mReader = ImageReader.newInstance(mTileWidth, mTileHeight, PixelFormat.RGBA_8888,
MAX_TILES, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE); MAX_TILES, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
mStartCompleter = completer; mStartCompleter = completer;
mReader.setOnImageAvailableListenerWithExecutor(this, mBgExecutor);
try { try {
mCancellationSignal = mConnection.startCapture(mReader.getSurface(), this); mCancellationSignal = mConnection.startCapture(mReader.getSurface(), this);
completer.addCancellationListener(() -> { completer.addCancellationListener(() -> {
@@ -339,9 +352,34 @@ public class ScrollCaptureClient {
@BinderThread @BinderThread
@Override @Override
public void onImageRequestCompleted(int flags, Rect contentArea) { public void onImageRequestCompleted(int flagsUnused, Rect contentArea) {
Image image = mReader.acquireLatestImage(); synchronized (mLock) {
mTileRequestCompleter.set(new CaptureResult(image, mRequestRect, contentArea)); mCapturedArea = contentArea;
if (mCapturedImage != null || (mCapturedArea == null || mCapturedArea.isEmpty())) {
completeCaptureRequest();
}
}
}
/** @see ImageReader.OnImageAvailableListener */
@Override
public void onImageAvailable(ImageReader reader) {
synchronized (mLock) {
mCapturedImage = mReader.acquireLatestImage();
if (mCapturedArea != null) {
completeCaptureRequest();
}
}
}
/** Produces a result for the caller as soon as both asynchronous results are received. */
private void completeCaptureRequest() {
CaptureResult result =
new CaptureResult(mCapturedImage, mRequestRect, mCapturedArea);
mCapturedImage = null;
mRequestRect = null;
mCapturedArea = null;
mTileRequestCompleter.set(result);
} }
@Override @Override

View File

@@ -26,7 +26,6 @@ import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import android.content.Context;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.RemoteException; import android.os.RemoteException;
import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner;
@@ -36,7 +35,6 @@ import android.view.IWindowManager;
import android.view.ScrollCaptureResponse; import android.view.ScrollCaptureResponse;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestCase;
import com.android.systemui.screenshot.ScrollCaptureClient.CaptureResult; import com.android.systemui.screenshot.ScrollCaptureClient.CaptureResult;
@@ -83,7 +81,7 @@ public class ScrollCaptureClientTest extends SysuiTestCase {
/* taskId */ anyInt(), any(IScrollCaptureResponseListener.class)); /* taskId */ anyInt(), any(IScrollCaptureResponseListener.class));
// Create client // Create client
ScrollCaptureClient client = new ScrollCaptureClient(mContext, mWm); ScrollCaptureClient client = new ScrollCaptureClient(mWm, Runnable::run, mContext);
// Request scroll capture // Request scroll capture
ListenableFuture<ScrollCaptureResponse> requestFuture = ListenableFuture<ScrollCaptureResponse> requestFuture =