Merge "Avoid NPE on ScrollCaptureConnection callbacks" into tm-dev

This commit is contained in:
TreeHugger Robot
2022-05-19 06:43:31 +00:00
committed by Android (Google) Code Review
2 changed files with 76 additions and 4 deletions

View File

@@ -144,8 +144,13 @@ public class ScrollCaptureConnection extends IScrollCaptureConnection.Stub imple
Consumer<Rect> listener = Consumer<Rect> listener =
SafeCallback.create(mCancellation, mUiThread, this::onImageRequestCompleted); SafeCallback.create(mCancellation, mUiThread, this::onImageRequestCompleted);
// -> UiThread // -> UiThread
mUiThread.execute(() -> mLocal.onScrollCaptureImageRequest( mUiThread.execute(() -> {
mSession, mCancellation, new Rect(requestRect), listener)); if (mLocal != null) {
mLocal.onScrollCaptureImageRequest(
mSession, mCancellation, new Rect(requestRect), listener);
}
});
return cancellation; return cancellation;
} }
@@ -174,7 +179,11 @@ public class ScrollCaptureConnection extends IScrollCaptureConnection.Stub imple
Runnable listener = Runnable listener =
SafeCallback.create(mCancellation, mUiThread, this::onEndCaptureCompleted); SafeCallback.create(mCancellation, mUiThread, this::onEndCaptureCompleted);
// -> UiThread // -> UiThread
mUiThread.execute(() -> mLocal.onScrollCaptureEnd(listener)); mUiThread.execute(() -> {
if (mLocal != null) {
mLocal.onScrollCaptureEnd(listener);
}
});
return cancellation; return cancellation;
} }

View File

@@ -47,6 +47,10 @@ import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.concurrent.Executor;
/** /**
* Tests of {@link ScrollCaptureConnection}. * Tests of {@link ScrollCaptureConnection}.
*/ */
@@ -56,6 +60,7 @@ import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class ScrollCaptureConnectionTest { public class ScrollCaptureConnectionTest {
private final Point mPositionInWindow = new Point(1, 2); private final Point mPositionInWindow = new Point(1, 2);
private final Rect mLocalVisibleRect = new Rect(2, 3, 4, 5); private final Rect mLocalVisibleRect = new Rect(2, 3, 4, 5);
private final Rect mScrollBounds = new Rect(3, 4, 5, 6); private final Rect mScrollBounds = new Rect(3, 4, 5, 6);
@@ -73,6 +78,9 @@ public class ScrollCaptureConnectionTest {
private IScrollCaptureCallbacks mRemote; private IScrollCaptureCallbacks mRemote;
@Mock @Mock
private View mView; private View mView;
private FakeExecutor mFakeUiThread;
private final Executor mImmediateExecutor = Runnable::run;
@Before @Before
public void setUp() { public void setUp() {
@@ -84,7 +92,9 @@ public class ScrollCaptureConnectionTest {
mTarget = new ScrollCaptureTarget(mView, mLocalVisibleRect, mPositionInWindow, mCallback); mTarget = new ScrollCaptureTarget(mView, mLocalVisibleRect, mPositionInWindow, mCallback);
mTarget.setScrollBounds(mScrollBounds); mTarget.setScrollBounds(mScrollBounds);
mConnection = new ScrollCaptureConnection(Runnable::run, mTarget); mFakeUiThread = new FakeExecutor();
mFakeUiThread.setImmediate(true);
mConnection = new ScrollCaptureConnection(mFakeUiThread, mTarget);
} }
/** Test creating a client with valid info */ /** Test creating a client with valid info */
@@ -145,6 +155,21 @@ public class ScrollCaptureConnectionTest {
.onImageRequestCompleted(eq(0), eq(new Rect(1, 2, 3, 4))); .onImageRequestCompleted(eq(0), eq(new Rect(1, 2, 3, 4)));
} }
/** Test closing while callbacks are in-flight: b/232375183 */
@Test
public void testRequestImage_afterClose() throws Exception {
mConnection = new ScrollCaptureConnection(mFakeUiThread, mTarget);
mConnection.startCapture(mSurface, mRemote);
mCallback.completeStartRequest();
mFakeUiThread.setImmediate(false);
mConnection.requestImage(new Rect(1, 2, 3, 4));
// Now close connection, before the UI thread executes
mConnection.close();
mFakeUiThread.runAll();
}
@Test @Test
public void testRequestImage_cancellation() throws Exception { public void testRequestImage_cancellation() throws Exception {
mConnection.startCapture(mSurface, mRemote); mConnection.startCapture(mSurface, mRemote);
@@ -176,6 +201,20 @@ public class ScrollCaptureConnectionTest {
assertFalse(mConnection.isConnected()); assertFalse(mConnection.isConnected());
} }
/** Test closing while callbacks are in-flight: b/232375183 */
@Test
public void testEndCapture_afterClose() throws Exception {
mConnection.startCapture(mSurface, mRemote);
mCallback.completeStartRequest();
mFakeUiThread.setImmediate(false);
mConnection.endCapture();
// Now close connection, before the UI thread executes
mConnection.close();
mFakeUiThread.runAll();
}
/** @see ScrollCaptureConnection#endCapture() */ /** @see ScrollCaptureConnection#endCapture() */
@Test @Test
public void testClose_withPendingOperation() throws Exception { public void testClose_withPendingOperation() throws Exception {
@@ -229,4 +268,28 @@ public class ScrollCaptureConnectionTest {
assertFalse(mConnection.isActive()); assertFalse(mConnection.isActive());
assertFalse(mConnection.isConnected()); assertFalse(mConnection.isConnected());
} }
static class FakeExecutor implements Executor {
private Queue<Runnable> mQueue = new ArrayDeque<>();
private boolean mImmediate;
@Override
public void execute(Runnable command) {
if (mImmediate) {
command.run();
} else {
mQueue.add(command);
}
}
void setImmediate(boolean immediate) {
mImmediate = immediate;
}
public void runAll() {
while (!mQueue.isEmpty()) {
mQueue.remove().run();
}
}
}
} }