Merge "Input: Update input window info when the layer receives its first buffer"
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 86e9c23..60542bd 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -24,11 +24,15 @@
#include <memory>
+#include <android/native_window.h>
+
#include <binder/Binder.h>
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SurfaceControl.h>
@@ -37,6 +41,7 @@
#include <input/InputTransport.h>
#include <input/Input.h>
+#include <ui/DisplayInfo.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -44,6 +49,8 @@
namespace android {
namespace test {
+using Transaction = SurfaceComposerClient::Transaction;
+
sp<IInputFlinger> getInputFlinger() {
sp<IBinder> input(defaultServiceManager()->getService(
String16("inputflinger")));
@@ -58,9 +65,8 @@
class InputSurface {
public:
- InputSurface(const sp<SurfaceComposerClient>& scc, int width, int height) {
- mSurfaceControl = scc->createSurface(String8("Test Surface"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor);
+ InputSurface(const sp<SurfaceControl> &sc, int width, int height) {
+ mSurfaceControl = sc;
InputChannel::openInputChannelPair("testchannels", mServerChannel, mClientChannel);
mServerChannel->setToken(new BBinder());
@@ -73,6 +79,31 @@
mInputConsumer = new InputConsumer(mClientChannel);
}
+ static std::unique_ptr<InputSurface> makeColorInputSurface(const sp<SurfaceComposerClient> &scc,
+ int width, int height) {
+ sp<SurfaceControl> surfaceControl =
+ scc->createSurface(String8("Test Surface"), 0 /* bufHeight */, 0 /* bufWidth */,
+ PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
+ return std::make_unique<InputSurface>(surfaceControl, width, height);
+ }
+
+ static std::unique_ptr<InputSurface> makeBufferInputSurface(
+ const sp<SurfaceComposerClient> &scc, int width, int height) {
+ sp<SurfaceControl> surfaceControl =
+ scc->createSurface(String8("Test Buffer Surface"), width, height,
+ PIXEL_FORMAT_RGBA_8888, 0 /* flags */);
+ return std::make_unique<InputSurface>(surfaceControl, width, height);
+ }
+
+ static std::unique_ptr<InputSurface> makeContainerInputSurface(
+ const sp<SurfaceComposerClient> &scc, int width, int height) {
+ sp<SurfaceControl> surfaceControl =
+ scc->createSurface(String8("Test Container Surface"), 0 /* bufHeight */,
+ 0 /* bufWidth */, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceContainer);
+ return std::make_unique<InputSurface>(surfaceControl, width, height);
+ }
+
InputEvent* consumeEvent() {
waitForEventAvailable();
@@ -180,6 +211,15 @@
void SetUp() {
mComposerClient = new SurfaceComposerClient;
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+ DisplayInfo info;
+ auto display = mComposerClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+ SurfaceComposerClient::getDisplayInfo(display, &info);
+
+ // After a new buffer is queued, SurfaceFlinger is notified and will
+ // latch the new buffer on next vsync. Let's heuristically wait for 3
+ // vsyncs.
+ mBufferPostDelay = int32_t(1e6 / info.fps) * 3;
}
void TearDown() {
@@ -187,10 +227,23 @@
}
std::unique_ptr<InputSurface> makeSurface(int width, int height) {
- return std::make_unique<InputSurface>(mComposerClient, width, height);
+ return InputSurface::makeColorInputSurface(mComposerClient, width, height);
+ }
+
+ void postBuffer(const sp<SurfaceControl> &layer) {
+ // wait for previous transactions (such as setSize) to complete
+ Transaction().apply(true);
+ ANativeWindow_Buffer buffer = {};
+ EXPECT_EQ(NO_ERROR, layer->getSurface()->lock(&buffer, nullptr));
+ ASSERT_EQ(NO_ERROR, layer->getSurface()->unlockAndPost());
+ // Request an empty transaction to get applied synchronously to ensure the buffer is
+ // latched.
+ Transaction().apply(true);
+ usleep(mBufferPostDelay);
}
sp<SurfaceComposerClient> mComposerClient;
+ int32_t mBufferPostDelay;
};
void injectTap(int x, int y) {
@@ -267,5 +320,124 @@
surface->expectTap(1, 1);
}
+// Surface Insets are set to offset the client content and draw a border around the client surface
+// (such as shadows in dialogs). Inputs sent to the client are offset such that 0,0 is the start
+// of the client content.
+TEST_F(InputSurfacesTest, input_respects_surface_insets) {
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+ bgSurface->showAt(100, 100);
+
+ fgSurface->mInputInfo.surfaceInset = 5;
+ fgSurface->showAt(100, 100);
+
+ injectTap(106, 106);
+ fgSurface->expectTap(1, 1);
+
+ injectTap(101, 101);
+ bgSurface->expectTap(1, 1);
+}
+
+// Ensure a surface whose insets are cropped, handles the touch offset correctly. ref:b/120413463
+TEST_F(InputSurfacesTest, input_respects_cropped_surface_insets) {
+ std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> childSurface = makeSurface(100, 100);
+ parentSurface->showAt(100, 100);
+
+ childSurface->mInputInfo.surfaceInset = 10;
+ childSurface->showAt(100, 100);
+
+ childSurface->doTransaction([&](auto &t, auto &sc) {
+ t.setPosition(sc, -5, -5);
+ t.reparent(sc, parentSurface->mSurfaceControl->getHandle());
+ });
+
+ injectTap(106, 106);
+ childSurface->expectTap(1, 1);
+
+ injectTap(101, 101);
+ parentSurface->expectTap(1, 1);
+}
+
+// Ensure we ignore transparent region when getting screen bounds when positioning input frame.
+TEST_F(InputSurfacesTest, input_ignores_transparent_region) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->doTransaction([](auto &t, auto &sc) {
+ Region transparentRegion(Rect(0, 0, 10, 10));
+ t.setTransparentRegionHint(sc, transparentRegion);
+ });
+ surface->showAt(100, 100);
+ injectTap(101, 101);
+ surface->expectTap(1, 1);
+}
+
+// Ensure we send the input to the right surface when the surface visibility changes due to the
+// first buffer being submitted. ref: b/120839715
+TEST_F(InputSurfacesTest, input_respects_buffer_layer_buffer) {
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> bufferSurface =
+ InputSurface::makeBufferInputSurface(mComposerClient, 100, 100);
+
+ bgSurface->showAt(10, 10);
+ bufferSurface->showAt(10, 10);
+
+ injectTap(11, 11);
+ bgSurface->expectTap(1, 1);
+
+ postBuffer(bufferSurface->mSurfaceControl);
+ injectTap(11, 11);
+ bufferSurface->expectTap(1, 1);
+}
+
+TEST_F(InputSurfacesTest, input_respects_buffer_layer_alpha) {
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> bufferSurface =
+ InputSurface::makeBufferInputSurface(mComposerClient, 100, 100);
+ postBuffer(bufferSurface->mSurfaceControl);
+
+ bgSurface->showAt(10, 10);
+ bufferSurface->showAt(10, 10);
+
+ injectTap(11, 11);
+ bufferSurface->expectTap(1, 1);
+
+ bufferSurface->doTransaction([](auto &t, auto &sc) { t.setAlpha(sc, 0.0); });
+
+ injectTap(11, 11);
+ bgSurface->expectTap(1, 1);
+}
+
+TEST_F(InputSurfacesTest, input_respects_color_layer_alpha) {
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+
+ bgSurface->showAt(10, 10);
+ fgSurface->showAt(10, 10);
+
+ injectTap(11, 11);
+ fgSurface->expectTap(1, 1);
+
+ fgSurface->doTransaction([](auto &t, auto &sc) { t.setAlpha(sc, 0.0); });
+
+ injectTap(11, 11);
+ bgSurface->expectTap(1, 1);
+}
+
+TEST_F(InputSurfacesTest, input_respects_container_layer_visiblity) {
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> containerSurface =
+ InputSurface::makeContainerInputSurface(mComposerClient, 100, 100);
+
+ bgSurface->showAt(10, 10);
+ containerSurface->showAt(10, 10);
+
+ injectTap(11, 11);
+ containerSurface->expectTap(1, 1);
+
+ containerSurface->doTransaction([](auto &t, auto &sc) { t.hide(sc); });
+
+ injectTap(11, 11);
+ bgSurface->expectTap(1, 1);
+}
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 20e7f70..b68346f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2736,7 +2736,7 @@
commitTransaction();
- if ((inputChanged || mVisibleRegionsDirty) && mInputFlinger) {
+ if (inputChanged || mVisibleRegionsDirty) {
updateInputWindows();
}
@@ -2746,6 +2746,10 @@
void SurfaceFlinger::updateInputWindows() {
ATRACE_CALL();
+ if (mInputFlinger == nullptr) {
+ return;
+ }
+
Vector<InputWindowInfo> inputHandles;
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
@@ -3015,6 +3019,11 @@
mVisibleRegionsDirty |= visibleRegions;
+ if (visibleRegions) {
+ // Update input window info if the layer receives its first buffer.
+ updateInputWindows();
+ }
+
// If we will need to wake up at some time in the future to deal with a
// queued frame that shouldn't be displayed during this vsync period, wake
// up during the next vsync period to check again.