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 com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.dagger.qualifiers.Background;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.concurrent.Executor;
import javax.inject.Inject;
/**
@@ -63,6 +66,8 @@ public class ScrollCaptureClient {
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.
*/
@@ -155,8 +160,10 @@ public class ScrollCaptureClient {
private IBinder mHostWindowToken;
@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!");
mBgExecutor = bgExecutor;
mWindowManagerService = windowManagerService;
}
@@ -220,21 +227,25 @@ public class ScrollCaptureClient {
return "";
}
SessionWrapper session = new SessionWrapper(connection, response.getWindowBounds(),
response.getBoundsInWindow(), maxPages);
response.getBoundsInWindow(), maxPages, mBgExecutor);
session.start(completer);
return "IScrollCaptureCallbacks#onCaptureStarted";
});
}
private static class SessionWrapper extends IScrollCaptureCallbacks.Stub implements Session,
IBinder.DeathRecipient {
IBinder.DeathRecipient, ImageReader.OnImageAvailableListener {
private IScrollCaptureConnection mConnection;
private final Executor mBgExecutor;
private final Object mLock = new Object();
private ImageReader mReader;
private final int mTileHeight;
private final int mTileWidth;
private Rect mRequestRect;
private Rect mCapturedArea;
private Image mCapturedImage;
private boolean mStarted;
private final int mTargetHeight;
@@ -247,7 +258,8 @@ public class ScrollCaptureClient {
private Completer<Void> mEndCompleter;
private SessionWrapper(IScrollCaptureConnection connection, Rect windowBounds,
Rect boundsInWindow, float maxPages) throws RemoteException {
Rect boundsInWindow, float maxPages, Executor bgExecutor)
throws RemoteException {
mConnection = requireNonNull(connection);
mConnection.asBinder().linkToDeath(SessionWrapper.this, 0);
mWindowBounds = requireNonNull(windowBounds);
@@ -259,7 +271,7 @@ public class ScrollCaptureClient {
mTileWidth = mBoundsInWindow.width();
mTileHeight = pxPerTile / mBoundsInWindow.width();
mTargetHeight = (int) (mBoundsInWindow.height() * maxPages);
mBgExecutor = bgExecutor;
if (DEBUG_SCROLL) {
Log.d(TAG, "boundsInWindow: " + mBoundsInWindow);
Log.d(TAG, "tile size: " + mTileWidth + "x" + mTileHeight);
@@ -289,6 +301,7 @@ public class ScrollCaptureClient {
mReader = ImageReader.newInstance(mTileWidth, mTileHeight, PixelFormat.RGBA_8888,
MAX_TILES, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
mStartCompleter = completer;
mReader.setOnImageAvailableListenerWithExecutor(this, mBgExecutor);
try {
mCancellationSignal = mConnection.startCapture(mReader.getSurface(), this);
completer.addCancellationListener(() -> {
@@ -339,9 +352,34 @@ public class ScrollCaptureClient {
@BinderThread
@Override
public void onImageRequestCompleted(int flags, Rect contentArea) {
Image image = mReader.acquireLatestImage();
mTileRequestCompleter.set(new CaptureResult(image, mRequestRect, contentArea));
public void onImageRequestCompleted(int flagsUnused, Rect contentArea) {
synchronized (mLock) {
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

View File

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