Loading packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java +46 −8 Original line number Diff line number Diff line Loading @@ -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; /** Loading @@ -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. */ Loading Loading @@ -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; } Loading Loading @@ -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; Loading @@ -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); Loading @@ -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); Loading Loading @@ -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(() -> { Loading Loading @@ -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 Loading packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java +1 −3 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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 = Loading Loading
packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java +46 −8 Original line number Diff line number Diff line Loading @@ -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; /** Loading @@ -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. */ Loading Loading @@ -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; } Loading Loading @@ -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; Loading @@ -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); Loading @@ -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); Loading Loading @@ -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(() -> { Loading Loading @@ -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 Loading
packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java +1 −3 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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 = Loading