Merge "Use OnImageAvailableListener to wait for buffer" into sc-dev
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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 =
|
||||||
|
|||||||
Reference in New Issue
Block a user