Merge changes from topic "sfinput4"
* changes:
SurfaceFlinger Input: Correct screen magnification.
Remove inputflinger.rc as init file
SurfaceFlinger Input: Shrink frame by surfaceInsets.
InputDispatcher: Notify policy of focus changes.
Rework InputApplicationInfo
Replace InputWindowInfo#inputChannel with an IBinder token.
Add some tests for native input.
Forward input windows from SurfaceFlinger to InputDispatcher.
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
index 1ef8986..610834d 100644
--- a/include/input/IInputFlinger.h
+++ b/include/input/IInputFlinger.h
@@ -36,6 +36,9 @@
DECLARE_META_INTERFACE(InputFlinger)
virtual void setInputWindows(const Vector<InputWindowInfo>& inputHandles) = 0;
+
+ virtual void registerInputChannel(const sp<InputChannel>& channel) = 0;
+ virtual void unregisterInputChannel(const sp<InputChannel>& channel) = 0;
};
@@ -46,6 +49,8 @@
public:
enum {
SET_INPUT_WINDOWS_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+ REGISTER_INPUT_CHANNEL_TRANSACTION,
+ UNREGISTER_INPUT_CHANNEL_TRANSACTION
};
virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/include/input/Input.h b/include/input/Input.h
index cc45aef..ee22bc6 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -244,7 +244,12 @@
float getAxisValue(int32_t axis) const;
status_t setAxisValue(int32_t axis, float value);
- void scale(float scale);
+ void scale(float globalScale);
+
+ // Scale the pointer coordinates according to a global scale and a
+ // window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR
+ // axes, however the window scaling will not.
+ void scale(float globalScale, float windowXScale, float windowYScale);
void applyOffset(float xOffset, float yOffset);
inline float getX() const {
@@ -595,7 +600,7 @@
void offsetLocation(float xOffset, float yOffset);
- void scale(float scaleFactor);
+ void scale(float globalScaleFactor);
// Apply 3x3 perspective matrix transformation.
// Matrix is in row-major form and compatible with SkMatrix.
diff --git a/include/input/InputApplication.h b/include/input/InputApplication.h
index 9b365b9..71a8f20 100644
--- a/include/input/InputApplication.h
+++ b/include/input/InputApplication.h
@@ -19,6 +19,9 @@
#include <string>
+#include <binder/IBinder.h>
+#include <binder/Parcel.h>
+
#include <input/Input.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
@@ -29,8 +32,12 @@
* Describes the properties of an application that can receive input.
*/
struct InputApplicationInfo {
+ sp<IBinder> token;
std::string name;
nsecs_t dispatchingTimeout;
+
+ status_t write(Parcel& output) const;
+ static InputApplicationInfo read(const Parcel& from);
};
@@ -54,6 +61,10 @@
return mInfo ? mInfo->dispatchingTimeout : defaultValue;
}
+ inline sp<IBinder> getApplicationToken() const {
+ return mInfo ? mInfo->token : nullptr;
+ }
+
/**
* Requests that the state of this object be updated to reflect
* the most current available information about the application.
diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h
index 9e3d334..8dd95cf 100644
--- a/include/input/InputWindow.h
+++ b/include/input/InputWindow.h
@@ -116,17 +116,42 @@
INPUT_FEATURE_NO_INPUT_CHANNEL = 0x00000002,
INPUT_FEATURE_DISABLE_USER_ACTIVITY = 0x00000004,
};
-
- sp<InputChannel> inputChannel;
+
+ /* These values are filled in by the WM and passed through SurfaceFlinger
+ * unless specified otherwise.
+ */
+ sp<IBinder> token;
std::string name;
int32_t layoutParamsFlags;
int32_t layoutParamsType;
nsecs_t dispatchingTimeout;
+
+ /* These values are filled in by SurfaceFlinger. */
int32_t frameLeft;
int32_t frameTop;
int32_t frameRight;
int32_t frameBottom;
- float scaleFactor;
+
+ /*
+ * SurfaceFlinger consumes this value to shrink the computed frame. This is
+ * different from shrinking the touchable region in that it DOES shift the coordinate
+ * space where-as the touchable region does not and is more like "cropping". This
+ * is used for window shadows.
+ */
+ int32_t surfaceInset = 0;
+
+ // A global scaling factor for all windows. Unlike windowScaleX/Y this results
+ // in scaling of the TOUCH_MAJOR/TOUCH_MINOR axis.
+ float globalScaleFactor;
+
+ // Scaling factors applied to individual windows.
+ float windowXScale = 1.0f;
+ float windowYScale = 1.0f;
+
+ /*
+ * This is filled in by the WM relative to the frame and then translated
+ * to absolute coordinates by SurfaceFlinger once the frame is computed.
+ */
Region touchableRegion;
bool visible;
bool canReceiveKeys;
@@ -138,6 +163,7 @@
int32_t ownerUid;
int32_t inputFeatures;
int32_t displayId;
+ InputApplicationInfo applicationInfo;
void addTouchableRegion(const Rect& region);
@@ -168,20 +194,23 @@
*/
class InputWindowHandle : public RefBase {
public:
- const sp<InputApplicationHandle> inputApplicationHandle;
inline const InputWindowInfo* getInfo() const {
return &mInfo;
}
- sp<InputChannel> getInputChannel() const;
+ sp<IBinder> getToken() const;
+
+ sp<IBinder> getApplicationToken() {
+ return mInfo.applicationInfo.token;
+ }
inline std::string getName() const {
- return mInfo.inputChannel ? mInfo.name : "<invalid>";
+ return mInfo.token ? mInfo.name : "<invalid>";
}
inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
- return mInfo.inputChannel? mInfo.dispatchingTimeout : defaultValue;
+ return mInfo.token ? mInfo.dispatchingTimeout : defaultValue;
}
/**
@@ -202,7 +231,7 @@
void releaseChannel();
protected:
- explicit InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle);
+ explicit InputWindowHandle();
virtual ~InputWindowHandle();
InputWindowInfo mInfo;
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 7ecadf8..a6295e0 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -16,6 +16,7 @@
"BufferItemConsumer_test.cpp",
"BufferQueue_test.cpp",
"CpuConsumer_test.cpp",
+ "EndToEndNativeInputTest.cpp",
"FillBuffer.cpp",
"GLTest.cpp",
"IGraphicBufferProducer_test.cpp",
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
new file mode 100644
index 0000000..2871302
--- /dev/null
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <poll.h>
+
+#include <memory>
+
+#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
+
+#include <input/InputWindow.h>
+#include <input/IInputFlinger.h>
+#include <input/InputTransport.h>
+#include <input/Input.h>
+
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+
+namespace android {
+namespace test {
+
+sp<IInputFlinger> getInputFlinger() {
+ sp<IBinder> input(defaultServiceManager()->getService(
+ String16("inputflinger")));
+ if (input == nullptr) {
+ ALOGE("Failed to link to input service");
+ } else { ALOGE("Linked to input"); }
+ return interface_cast<IInputFlinger>(input);
+}
+
+// We use the top 10 layers as a way to haphazardly place ourselves above anything else.
+static const int LAYER_BASE = INT32_MAX - 10;
+
+class InputSurface {
+public:
+ InputSurface(const sp<SurfaceComposerClient>& scc, int width, int height) {
+ mSurfaceControl = scc->createSurface(String8("Test Surface"),
+ width, height, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor);
+
+ InputChannel::openInputChannelPair("testchannels", mServerChannel, mClientChannel);
+ mServerChannel->setToken(new BBinder());
+
+ mInputFlinger = getInputFlinger();
+ mInputFlinger->registerInputChannel(mServerChannel);
+
+ populateInputInfo(width, height);
+
+ mInputConsumer = new InputConsumer(mClientChannel);
+ }
+
+ InputEvent* consumeEvent() {
+ waitForEventAvailable();
+
+ InputEvent *ev;
+ uint32_t seqId;
+ status_t consumed = mInputConsumer->consume(&mInputEventFactory, true, -1, &seqId, &ev);
+ if (consumed != OK) {
+ return nullptr;
+ }
+ mInputConsumer->sendFinishedSignal(seqId, true);
+ return ev;
+ }
+
+ void expectTap(int x, int y) {
+ InputEvent* ev = consumeEvent();
+ EXPECT_TRUE(ev != nullptr);
+ EXPECT_TRUE(ev->getType() == AINPUT_EVENT_TYPE_MOTION);
+ MotionEvent* mev = static_cast<MotionEvent*>(ev);
+ EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, mev->getAction());
+ EXPECT_EQ(x, mev->getX(0));
+ EXPECT_EQ(y, mev->getY(0));
+
+ ev = consumeEvent();
+ EXPECT_TRUE(ev != nullptr);
+ EXPECT_TRUE(ev->getType() == AINPUT_EVENT_TYPE_MOTION);
+ mev = static_cast<MotionEvent*>(ev);
+ EXPECT_EQ(AMOTION_EVENT_ACTION_UP, mev->getAction());
+ }
+
+ ~InputSurface() {
+ mInputFlinger->unregisterInputChannel(mServerChannel);
+ }
+
+ void doTransaction(std::function<void(SurfaceComposerClient::Transaction&,
+ const sp<SurfaceControl>&)> transactionBody) {
+ SurfaceComposerClient::Transaction t;
+ transactionBody(t, mSurfaceControl);
+ t.apply(true);
+ }
+
+ void showAt(int x, int y) {
+ SurfaceComposerClient::Transaction t;
+ t.show(mSurfaceControl);
+ t.setInputWindowInfo(mSurfaceControl, mInputInfo);
+ t.setLayer(mSurfaceControl, LAYER_BASE);
+ t.setPosition(mSurfaceControl, x, y);
+ t.setCrop_legacy(mSurfaceControl, Rect(0, 0, 100, 100));
+ t.setAlpha(mSurfaceControl, 1);
+ t.apply(true);
+ }
+
+private:
+ void waitForEventAvailable() {
+ struct pollfd fd;
+
+ fd.fd = mClientChannel->getFd();
+ fd.events = POLLIN;
+ poll(&fd, 1, 3000);
+ }
+
+ void populateInputInfo(int width, int height) {
+ mInputInfo.token = mServerChannel->getToken();
+ mInputInfo.name = "Test info";
+ mInputInfo.layoutParamsFlags = InputWindowInfo::FLAG_NOT_TOUCH_MODAL;
+ mInputInfo.layoutParamsType = InputWindowInfo::TYPE_BASE_APPLICATION;
+ mInputInfo.dispatchingTimeout = 100000;
+ mInputInfo.globalScaleFactor = 1.0;
+ mInputInfo.canReceiveKeys = true;
+ mInputInfo.hasFocus = true;
+ mInputInfo.hasWallpaper = false;
+ mInputInfo.paused = false;
+
+ mInputInfo.touchableRegion.orSelf(Rect(0, 0, width, height));
+
+ // TODO: Fill in from SF?
+ mInputInfo.ownerPid = 11111;
+ mInputInfo.ownerUid = 11111;
+ mInputInfo.inputFeatures = 0;
+ mInputInfo.displayId = 0;
+
+ InputApplicationInfo aInfo;
+ aInfo.token = new BBinder();
+ aInfo.name = "Test app info";
+ aInfo.dispatchingTimeout = 100000;
+
+ mInputInfo.applicationInfo = aInfo;
+ }
+public:
+ sp<SurfaceControl> mSurfaceControl;
+ sp<InputChannel> mServerChannel, mClientChannel;
+ sp<IInputFlinger> mInputFlinger;
+
+ InputWindowInfo mInputInfo;
+
+ PreallocatedInputEventFactory mInputEventFactory;
+ InputConsumer* mInputConsumer;
+};
+
+class InputSurfacesTest : public ::testing::Test {
+public:
+ InputSurfacesTest() {
+ ProcessState::self()->startThreadPool();
+ }
+
+ void SetUp() {
+ mComposerClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+ }
+
+ void TearDown() {
+ mComposerClient->dispose();
+ }
+
+ std::unique_ptr<InputSurface> makeSurface(int width, int height) {
+ return std::make_unique<InputSurface>(mComposerClient, width, height);
+ }
+
+ sp<SurfaceComposerClient> mComposerClient;
+};
+
+void injectTap(int x, int y) {
+ char *buf1, *buf2;
+ asprintf(&buf1, "%d", x);
+ asprintf(&buf2, "%d", y);
+ if (fork() == 0) {
+ execlp("input", "input", "tap", buf1, buf2, NULL);
+ }
+}
+
+TEST_F(InputSurfacesTest, can_receive_input) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->showAt(100, 100);
+
+ injectTap(101, 101);
+
+ EXPECT_TRUE(surface->consumeEvent() != nullptr);
+}
+
+TEST_F(InputSurfacesTest, input_respects_positioning) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->showAt(100, 100);
+
+ std::unique_ptr<InputSurface> surface2 = makeSurface(100, 100);
+ surface2->showAt(200, 200);
+
+ injectTap(201, 201);
+ surface2->expectTap(1, 1);
+
+ injectTap(101, 101);
+ surface->expectTap(1, 1);
+
+ surface2->doTransaction([](auto &t, auto &sc) {
+ t.setPosition(sc, 100, 100);
+ });
+ surface->doTransaction([](auto &t, auto &sc) {
+ t.setPosition(sc, 200, 200);
+ });
+
+ injectTap(101, 101);
+ surface2->expectTap(1, 1);
+
+ injectTap(201, 201);
+ surface->expectTap(1, 1);
+}
+
+TEST_F(InputSurfacesTest, input_respects_layering) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> surface2 = makeSurface(100, 100);
+
+ surface->showAt(10, 10);
+ surface2->showAt(10, 10);
+
+ surface->doTransaction([](auto &t, auto &sc) {
+ t.setLayer(sc, LAYER_BASE + 1);
+ });
+
+ injectTap(11, 11);
+ surface->expectTap(1, 1);
+
+ surface2->doTransaction([](auto &t, auto &sc) {
+ t.setLayer(sc, LAYER_BASE + 1);
+ });
+
+ injectTap(11, 11);
+ surface2->expectTap(1, 1);
+
+ surface2->doTransaction([](auto &t, auto &sc) {
+ t.hide(sc);
+ });
+
+ injectTap(11, 11);
+ surface->expectTap(1, 1);
+}
+
+}
+}
diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp
index 47a2c0c..477e54e 100644
--- a/libs/input/IInputFlinger.cpp
+++ b/libs/input/IInputFlinger.cpp
@@ -40,6 +40,20 @@
}
remote()->transact(BnInputFlinger::SET_INPUT_WINDOWS_TRANSACTION, data, &reply);
}
+
+ virtual void registerInputChannel(const sp<InputChannel>& channel) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
+ channel->write(data);
+ remote()->transact(BnInputFlinger::REGISTER_INPUT_CHANNEL_TRANSACTION, data, &reply);
+ }
+
+ virtual void unregisterInputChannel(const sp<InputChannel>& channel) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
+ channel->write(data);
+ remote()->transact(BnInputFlinger::UNREGISTER_INPUT_CHANNEL_TRANSACTION, data, &reply);
+ }
};
IMPLEMENT_META_INTERFACE(InputFlinger, "android.input.IInputFlinger");
@@ -61,6 +75,20 @@
setInputWindows(handles);
break;
}
+ case REGISTER_INPUT_CHANNEL_TRANSACTION: {
+ CHECK_INTERFACE(IInputFlinger, data, reply);
+ sp<InputChannel> channel = new InputChannel();
+ channel->read(data);
+ registerInputChannel(channel);
+ break;
+ }
+ case UNREGISTER_INPUT_CHANNEL_TRANSACTION: {
+ CHECK_INTERFACE(IInputFlinger, data, reply);
+ sp<InputChannel> channel = new InputChannel();
+ channel->read(data);
+ unregisterInputChannel(channel);
+ break;
+ }
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 8a15e2f..a558970 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -131,15 +131,24 @@
}
}
-void PointerCoords::scale(float scaleFactor) {
+void PointerCoords::scale(float globalScaleFactor, float windowXScale, float windowYScale) {
// No need to scale pressure or size since they are normalized.
// No need to scale orientation since it is meaningless to do so.
- scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, scaleFactor);
- scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, scaleFactor);
- scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor);
- scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor);
- scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor);
- scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor);
+
+ // If there is a global scale factor, it is included in the windowX/YScale
+ // so we don't need to apply it twice to the X/Y axes.
+ // However we don't want to apply any windowXYScale not included in the global scale
+ // to the TOUCH_MAJOR/MINOR coordinates.
+ scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, windowXScale);
+ scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, windowYScale);
+ scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, globalScaleFactor);
+ scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, globalScaleFactor);
+ scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, globalScaleFactor);
+ scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, globalScaleFactor);
+}
+
+void PointerCoords::scale(float globalScaleFactor) {
+ scale(globalScaleFactor, globalScaleFactor, globalScaleFactor);
}
void PointerCoords::applyOffset(float xOffset, float yOffset) {
@@ -345,15 +354,15 @@
mYOffset += yOffset;
}
-void MotionEvent::scale(float scaleFactor) {
- mXOffset *= scaleFactor;
- mYOffset *= scaleFactor;
- mXPrecision *= scaleFactor;
- mYPrecision *= scaleFactor;
+void MotionEvent::scale(float globalScaleFactor) {
+ mXOffset *= globalScaleFactor;
+ mYOffset *= globalScaleFactor;
+ mXPrecision *= globalScaleFactor;
+ mYPrecision *= globalScaleFactor;
size_t numSamples = mSamplePointerCoords.size();
for (size_t i = 0; i < numSamples; i++) {
- mSamplePointerCoords.editItemAt(i).scale(scaleFactor);
+ mSamplePointerCoords.editItemAt(i).scale(globalScaleFactor);
}
}
diff --git a/libs/input/InputApplication.cpp b/libs/input/InputApplication.cpp
index a0d1668..7936f50 100644
--- a/libs/input/InputApplication.cpp
+++ b/libs/input/InputApplication.cpp
@@ -39,4 +39,21 @@
}
}
+InputApplicationInfo InputApplicationInfo::read(const Parcel& from) {
+ InputApplicationInfo ret;
+ ret.token = from.readStrongBinder();
+ ret.name = from.readString8().c_str();
+ ret.dispatchingTimeout = from.readInt64();
+
+ return ret;
+}
+
+status_t InputApplicationInfo::write(Parcel& output) const {
+ output.writeStrongBinder(token);
+ output.writeString8(String8(name.c_str()));
+ output.writeInt64(dispatchingTimeout);
+
+ return OK;
+}
+
} // namespace android
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
index f82437e..556a005 100644
--- a/libs/input/InputWindow.cpp
+++ b/libs/input/InputWindow.cpp
@@ -65,12 +65,12 @@
}
status_t InputWindowInfo::write(Parcel& output) const {
- if (inputChannel == nullptr) {
+ if (token == nullptr) {
output.writeInt32(0);
return OK;
}
output.writeInt32(1);
- status_t s = inputChannel->write(output);
+ status_t s = output.writeStrongBinder(token);
if (s != OK) return s;
output.writeString8(String8(name.c_str()));
@@ -81,7 +81,10 @@
output.writeInt32(frameTop);
output.writeInt32(frameRight);
output.writeInt32(frameBottom);
- output.writeFloat(scaleFactor);
+ output.writeInt32(surfaceInset);
+ output.writeFloat(globalScaleFactor);
+ output.writeFloat(windowXScale);
+ output.writeFloat(windowYScale);
output.writeBool(visible);
output.writeBool(canReceiveKeys);
output.writeBool(hasFocus);
@@ -92,6 +95,7 @@
output.writeInt32(ownerUid);
output.writeInt32(inputFeatures);
output.writeInt32(displayId);
+ applicationInfo.write(output);
output.write(touchableRegion);
return OK;
@@ -102,15 +106,14 @@
if (from.readInt32() == 0) {
return ret;
-
}
- sp<InputChannel> inputChannel = new InputChannel();
- status_t s = inputChannel->read(from);
- if (s != OK) {
+
+ sp<IBinder> token = from.readStrongBinder();
+ if (token == nullptr) {
return ret;
}
- ret.inputChannel = inputChannel;
+ ret.token = token;
ret.name = from.readString8().c_str();
ret.layoutParamsFlags = from.readInt32();
ret.layoutParamsType = from.readInt32();
@@ -119,7 +122,10 @@
ret.frameTop = from.readInt32();
ret.frameRight = from.readInt32();
ret.frameBottom = from.readInt32();
- ret.scaleFactor = from.readFloat();
+ ret.surfaceInset = from.readInt32();
+ ret.globalScaleFactor = from.readFloat();
+ ret.windowXScale = from.readFloat();
+ ret.windowYScale = from.readFloat();
ret.visible = from.readBool();
ret.canReceiveKeys = from.readBool();
ret.hasFocus = from.readBool();
@@ -130,6 +136,7 @@
ret.ownerUid = from.readInt32();
ret.inputFeatures = from.readInt32();
ret.displayId = from.readInt32();
+ ret.applicationInfo = InputApplicationInfo::read(from);
from.read(ret.touchableRegion);
return ret;
@@ -141,19 +148,18 @@
// --- InputWindowHandle ---
-InputWindowHandle::InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
- inputApplicationHandle(inputApplicationHandle) {
+InputWindowHandle::InputWindowHandle() {
}
InputWindowHandle::~InputWindowHandle() {
}
void InputWindowHandle::releaseChannel() {
- mInfo.inputChannel.clear();
+ mInfo.token.clear();
}
-sp<InputChannel> InputWindowHandle::getInputChannel() const {
- return mInfo.inputChannel;
+sp<IBinder> InputWindowHandle::getToken() const {
+ return mInfo.token;
}
} // namespace android
diff --git a/libs/input/tests/InputWindow_test.cpp b/libs/input/tests/InputWindow_test.cpp
index 39ad26e..5e5893f 100644
--- a/libs/input/tests/InputWindow_test.cpp
+++ b/libs/input/tests/InputWindow_test.cpp
@@ -16,6 +16,7 @@
#include <gtest/gtest.h>
+#include <binder/Binder.h>
#include <binder/Parcel.h>
#include <input/InputWindow.h>
@@ -24,24 +25,20 @@
namespace android {
namespace test {
-TEST(InputWindowInfo, ParcellingWithoutChannel) {
+TEST(InputWindowInfo, ParcellingWithoutToken) {
InputWindowInfo i;
- i.inputChannel = nullptr;
+ i.token = nullptr;
Parcel p;
ASSERT_EQ(OK, i.write(p));
p.setDataPosition(0);
InputWindowInfo i2 = InputWindowInfo::read(p);
- ASSERT_TRUE(i2.inputChannel == nullptr);
+ ASSERT_TRUE(i2.token == nullptr);
}
TEST(InputWindowInfo, Parcelling) {
- sp<InputChannel> channel, junkChannel;
- status_t result = InputChannel::openInputChannelPair("name", channel, junkChannel);
- ASSERT_EQ(OK, result) << "openInputChannelPair should have returned valid channels";
-
InputWindowInfo i;
- i.inputChannel = channel;
+ i.token = new BBinder();
i.name = "Foobar";
i.layoutParamsFlags = 7;
i.layoutParamsType = 39;
@@ -50,7 +47,10 @@
i.frameTop = 34;
i.frameRight = 16;
i.frameBottom = 19;
- i.scaleFactor = 0.3;
+ i.surfaceInset = 17;
+ i.globalScaleFactor = 0.3;
+ i.windowXScale = 0.4;
+ i.windowYScale = 0.5;
i.visible = false;
i.canReceiveKeys = false;
i.hasFocus = false;
@@ -67,7 +67,7 @@
p.setDataPosition(0);
InputWindowInfo i2 = InputWindowInfo::read(p);
- ASSERT_EQ(i.inputChannel->getName(), i2.inputChannel->getName());
+ ASSERT_EQ(i.token, i2.token);
ASSERT_EQ(i.name, i2.name);
ASSERT_EQ(i.layoutParamsFlags, i2.layoutParamsFlags);
ASSERT_EQ(i.layoutParamsType, i2.layoutParamsType);
@@ -76,7 +76,10 @@
ASSERT_EQ(i.frameTop, i2.frameTop);
ASSERT_EQ(i.frameRight, i2.frameRight);
ASSERT_EQ(i.frameBottom, i2.frameBottom);
- ASSERT_EQ(i.scaleFactor, i2.scaleFactor);
+ ASSERT_EQ(i.surfaceInset, i2.surfaceInset);
+ ASSERT_EQ(i.globalScaleFactor, i2.globalScaleFactor);
+ ASSERT_EQ(i.windowXScale, i2.windowXScale);
+ ASSERT_EQ(i.windowYScale, i2.windowYScale);
ASSERT_EQ(i.visible, i2.visible);
ASSERT_EQ(i.canReceiveKeys, i2.canReceiveKeys);
ASSERT_EQ(i.hasFocus, i2.hasFocus);
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index fe4ae6c..8150931 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -325,6 +325,20 @@
return *this;
}
+Region& Region::scaleSelf(int sx, int sy) {
+ size_t count = mStorage.size();
+ Rect* rects = mStorage.editArray();
+ while (count) {
+ rects->left *= sx;
+ rects->right *= sx;
+ rects->top *= sy;
+ rects->bottom *= sy;
+ rects++;
+ count--;
+ }
+ return *this;
+}
+
// ----------------------------------------------------------------------------
const Region Region::merge(const Rect& rhs) const {
diff --git a/libs/ui/Transform.cpp b/libs/ui/Transform.cpp
index 8e949ec..25128ef 100644
--- a/libs/ui/Transform.cpp
+++ b/libs/ui/Transform.cpp
@@ -95,6 +95,14 @@
return mMatrix[2][1];
}
+float Transform::sx() const {
+ return mMatrix[0][0];
+}
+
+float Transform::sy() const {
+ return mMatrix[1][1];
+}
+
void Transform::reset() {
mType = IDENTITY;
for(size_t i = 0; i < 3; i++) {
diff --git a/libs/ui/include/ui/Region.h b/libs/ui/include/ui/Region.h
index 68b60fc..c5e31c5 100644
--- a/libs/ui/include/ui/Region.h
+++ b/libs/ui/include/ui/Region.h
@@ -89,11 +89,13 @@
// these translate rhs first
Region& translateSelf(int dx, int dy);
+ Region& scaleSelf(int sx, int sy);
Region& orSelf(const Region& rhs, int dx, int dy);
Region& xorSelf(const Region& rhs, int dx, int dy);
Region& andSelf(const Region& rhs, int dx, int dy);
Region& subtractSelf(const Region& rhs, int dx, int dy);
+
// these translate rhs first
const Region translate(int dx, int dy) const WARN_UNUSED;
const Region merge(const Region& rhs, int dx, int dy) const WARN_UNUSED;
diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h
index 42dca75..900a5c4 100644
--- a/libs/ui/include/ui/Transform.h
+++ b/libs/ui/include/ui/Transform.h
@@ -65,6 +65,8 @@
const vec3& operator [] (size_t i) const; // returns column i
float tx() const;
float ty() const;
+ float sx() const;
+ float sy() const;
// modify the transform
void reset();
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 0c9e04b..bea4f91 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -489,7 +489,7 @@
if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN
&& (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
&& mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
- && mInputTargetWaitApplicationHandle != nullptr) {
+ && mInputTargetWaitApplicationToken != nullptr) {
int32_t displayId = motionEntry->displayId;
int32_t x = int32_t(motionEntry->pointerCoords[0].
getAxisValue(AMOTION_EVENT_AXIS_X));
@@ -497,8 +497,8 @@
getAxisValue(AMOTION_EVENT_AXIS_Y));
sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y);
if (touchedWindowHandle != nullptr
- && touchedWindowHandle->inputApplicationHandle
- != mInputTargetWaitApplicationHandle) {
+ && touchedWindowHandle->getApplicationToken()
+ != mInputTargetWaitApplicationToken) {
// User touched a different application than the one we are waiting on.
// Flag the event, and start pruning the input queue.
mNextUnblockedEvent = motionEntry;
@@ -819,7 +819,8 @@
sp<InputWindowHandle> focusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry));
if (focusedWindowHandle != nullptr) {
- commandEntry->inputChannel = focusedWindowHandle->getInputChannel();
+ commandEntry->inputChannel =
+ getInputChannelLocked(focusedWindowHandle->getToken());
}
commandEntry->keyEntry = entry;
entry->refCount += 1;
@@ -1010,7 +1011,7 @@
mInputTargetWaitStartTime = currentTime;
mInputTargetWaitTimeoutTime = LONG_LONG_MAX;
mInputTargetWaitTimeoutExpired = false;
- mInputTargetWaitApplicationHandle.clear();
+ mInputTargetWaitApplicationToken.clear();
}
} else {
if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
@@ -1033,13 +1034,13 @@
mInputTargetWaitStartTime = currentTime;
mInputTargetWaitTimeoutTime = currentTime + timeout;
mInputTargetWaitTimeoutExpired = false;
- mInputTargetWaitApplicationHandle.clear();
+ mInputTargetWaitApplicationToken.clear();
if (windowHandle != nullptr) {
- mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle;
+ mInputTargetWaitApplicationToken = windowHandle->getApplicationToken();
}
- if (mInputTargetWaitApplicationHandle == nullptr && applicationHandle != nullptr) {
- mInputTargetWaitApplicationHandle = applicationHandle;
+ if (mInputTargetWaitApplicationToken == nullptr && applicationHandle != nullptr) {
+ mInputTargetWaitApplicationToken = applicationHandle->getApplicationToken();
}
}
}
@@ -1117,7 +1118,7 @@
// Reset input target wait timeout.
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
- mInputTargetWaitApplicationHandle.clear();
+ mInputTargetWaitApplicationToken.clear();
}
/**
@@ -1666,11 +1667,13 @@
const InputWindowInfo* windowInfo = windowHandle->getInfo();
InputTarget& target = inputTargets.editTop();
- target.inputChannel = windowInfo->inputChannel;
+ target.inputChannel = getInputChannelLocked(windowHandle->getToken());
target.flags = targetFlags;
target.xOffset = - windowInfo->frameLeft;
target.yOffset = - windowInfo->frameTop;
- target.scaleFactor = windowInfo->scaleFactor;
+ target.globalScaleFactor = windowInfo->globalScaleFactor;
+ target.windowXScale = windowInfo->windowXScale;
+ target.windowYScale = windowInfo->windowYScale;
target.pointerIds = pointerIds;
}
@@ -1691,7 +1694,7 @@
target.xOffset = 0;
target.yOffset = 0;
target.pointerIds.clear();
- target.scaleFactor = 1.0f;
+ target.globalScaleFactor = 1.0f;
}
} else {
// If there is no monitor channel registered or all monitor channel unregistered,
@@ -1773,7 +1776,8 @@
}
// If the window's connection is not registered then keep waiting.
- ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel());
+ ssize_t connectionIndex = getConnectionIndexLocked(
+ getInputChannelLocked(windowHandle->getToken()));
if (connectionIndex < 0) {
return StringPrintf("Waiting because the %s window's input channel is not "
"registered with the input dispatcher. The window may be in the process "
@@ -1910,11 +1914,13 @@
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
- "xOffset=%f, yOffset=%f, scaleFactor=%f, "
- "pointerIds=0x%x",
+ "xOffset=%f, yOffset=%f, globalScaleFactor=%f, "
+ "windowScaleFactor=(%f, %f), pointerIds=0x%x",
connection->getInputChannelName().c_str(), inputTarget->flags,
inputTarget->xOffset, inputTarget->yOffset,
- inputTarget->scaleFactor, inputTarget->pointerIds.value);
+ inputTarget->globalScaleFactor,
+ inputTarget->windowXScale, inputTarget->windowYScale,
+ inputTarget->pointerIds.value);
#endif
// Skip this event if the connection status is not normal.
@@ -1991,7 +1997,8 @@
// Enqueue a new dispatch entry onto the outbound queue for this connection.
DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref
inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
- inputTarget->scaleFactor);
+ inputTarget->globalScaleFactor, inputTarget->windowXScale,
+ inputTarget->windowYScale);
// Apply target flags and update the connection's input state.
switch (eventEntry->type) {
@@ -2107,13 +2114,15 @@
float xOffset, yOffset;
if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
&& !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
- float scaleFactor = dispatchEntry->scaleFactor;
- xOffset = dispatchEntry->xOffset * scaleFactor;
- yOffset = dispatchEntry->yOffset * scaleFactor;
- if (scaleFactor != 1.0f) {
+ float globalScaleFactor = dispatchEntry->globalScaleFactor;
+ float wxs = dispatchEntry->windowXScale;
+ float wys = dispatchEntry->windowYScale;
+ xOffset = dispatchEntry->xOffset * wxs;
+ yOffset = dispatchEntry->yOffset * wys;
+ if (wxs != 1.0f || wys != 1.0f || globalScaleFactor != 1.0f) {
for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
scaledCoords[i] = motionEntry->pointerCoords[i];
- scaledCoords[i].scale(scaleFactor);
+ scaledCoords[i].scale(globalScaleFactor, wxs, wys);
}
usingCoords = scaledCoords;
}
@@ -2371,11 +2380,13 @@
const InputWindowInfo* windowInfo = windowHandle->getInfo();
target.xOffset = -windowInfo->frameLeft;
target.yOffset = -windowInfo->frameTop;
- target.scaleFactor = windowInfo->scaleFactor;
+ target.globalScaleFactor = windowInfo->globalScaleFactor;
+ target.windowXScale = windowInfo->windowXScale;
+ target.windowYScale = windowInfo->windowYScale;
} else {
target.xOffset = 0;
target.yOffset = 0;
- target.scaleFactor = 1.0f;
+ target.globalScaleFactor = 1.0f;
}
target.inputChannel = connection->inputChannel;
target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
@@ -3004,7 +3015,7 @@
size_t numWindows = windowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
- if (windowHandle->getInputChannel() == inputChannel) {
+ if (windowHandle->getToken() == inputChannel->getToken()) {
return windowHandle;
}
}
@@ -3018,8 +3029,8 @@
const Vector<sp<InputWindowHandle>> windowHandles = it.second;
size_t numWindows = windowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
- if (windowHandles.itemAt(i)->getInputChannel()->getToken()
- == windowHandle->getInputChannel()->getToken()) {
+ if (windowHandles.itemAt(i)->getToken()
+ == windowHandle->getToken()) {
if (windowHandle->getInfo()->displayId != it.first) {
ALOGE("Found window %s in display %" PRId32
", but it should belong to display %" PRId32,
@@ -3033,6 +3044,14 @@
return false;
}
+sp<InputChannel> InputDispatcher::getInputChannelLocked(const sp<IBinder>& token) const {
+ size_t count = mInputChannelsByToken.count(token);
+ if (count == 0) {
+ return nullptr;
+ }
+ return mInputChannelsByToken.at(token);
+}
+
/**
* Called from InputManagerService, update window handle list by displayId that can receive input.
* A window handle contains information about InputChannel, Touch Region, Types, Focused,...
@@ -3061,7 +3080,9 @@
size_t numWindows = inputWindowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
const sp<InputWindowHandle>& windowHandle = inputWindowHandles.itemAt(i);
- if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == nullptr) {
+ if (!windowHandle->updateInfo() || getInputChannelLocked(windowHandle->getToken()) == nullptr) {
+ ALOGE("Window handle %s has no registered input channel",
+ windowHandle->getName().c_str());
continue;
}
@@ -3097,7 +3118,8 @@
ALOGD("Focus left window: %s in display %" PRId32,
oldFocusedWindowHandle->getName().c_str(), displayId);
#endif
- sp<InputChannel> focusedInputChannel = oldFocusedWindowHandle->getInputChannel();
+ sp<InputChannel> focusedInputChannel = getInputChannelLocked(
+ oldFocusedWindowHandle->getToken());
if (focusedInputChannel != nullptr) {
CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
"focus left window");
@@ -3113,6 +3135,11 @@
#endif
mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle;
}
+
+ if (mFocusedDisplayId == displayId) {
+ onFocusChangedLocked(newFocusedWindowHandle);
+ }
+
}
ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId);
@@ -3126,7 +3153,7 @@
touchedWindow.windowHandle->getName().c_str(), displayId);
#endif
sp<InputChannel> touchedInputChannel =
- touchedWindow.windowHandle->getInputChannel();
+ getInputChannelLocked(touchedWindow.windowHandle->getToken());
if (touchedInputChannel != nullptr) {
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
"touched window was removed");
@@ -3214,7 +3241,8 @@
sp<InputWindowHandle> oldFocusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, mFocusedDisplayId);
if (oldFocusedWindowHandle != nullptr) {
- sp<InputChannel> inputChannel = oldFocusedWindowHandle->getInputChannel();
+ sp<InputChannel> inputChannel =
+ getInputChannelLocked(oldFocusedWindowHandle->getToken());
if (inputChannel != nullptr) {
CancelationOptions options(
CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS,
@@ -3227,6 +3255,8 @@
// Sanity check
sp<InputWindowHandle> newFocusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
+ onFocusChangedLocked(newFocusedWindowHandle);
+
if (newFocusedWindowHandle == nullptr) {
ALOGW("Focused display #%" PRId32 " does not have a focused window.", displayId);
if (!mFocusedWindowHandlesByDisplay.empty()) {
@@ -3488,7 +3518,7 @@
dump += StringPrintf(INDENT3 "%zu: name='%s', displayId=%d, "
"paused=%s, hasFocus=%s, hasWallpaper=%s, "
"visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
- "frame=[%d,%d][%d,%d], scale=%f, "
+ "frame=[%d,%d][%d,%d], globalScale=%f, windowScale=%f,%f"
"touchableRegion=",
i, windowInfo->name.c_str(), windowInfo->displayId,
toString(windowInfo->paused),
@@ -3500,7 +3530,8 @@
windowInfo->layer,
windowInfo->frameLeft, windowInfo->frameTop,
windowInfo->frameRight, windowInfo->frameBottom,
- windowInfo->scaleFactor);
+ windowInfo->globalScaleFactor,
+ windowInfo->windowXScale, windowInfo->windowYScale);
dumpRegion(dump, windowInfo->touchableRegion);
dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures);
dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
@@ -3667,6 +3698,7 @@
int fd = inputChannel->getFd();
mConnectionsByFd.add(fd, connection);
+ mInputChannelsByToken[inputChannel->getToken()] = inputChannel;
// Store monitor channel by displayId.
if (monitor) {
@@ -3715,6 +3747,8 @@
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
mConnectionsByFd.removeItemsAt(connectionIndex);
+ mInputChannelsByToken.erase(inputChannel->getToken());
+
if (connection->monitor) {
removeMonitorChannelLocked(inputChannel);
}
@@ -3782,6 +3816,13 @@
commandEntry->connection = connection;
}
+void InputDispatcher::onFocusChangedLocked(const sp<InputWindowHandle>& newFocus) {
+ sp<IBinder> token = newFocus != nullptr ? newFocus->getToken() : nullptr;
+ CommandEntry* commandEntry = postCommandLocked(
+ & InputDispatcher::doNotifyFocusChangedLockedInterruptible);
+ commandEntry->token = token;
+}
+
void InputDispatcher::onANRLocked(
nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle,
@@ -3812,7 +3853,8 @@
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doNotifyANRLockedInterruptible);
commandEntry->inputApplicationHandle = applicationHandle;
- commandEntry->inputChannel = windowHandle != nullptr ? windowHandle->getInputChannel() : nullptr;
+ commandEntry->inputChannel = windowHandle != nullptr ?
+ getInputChannelLocked(windowHandle->getToken()) : nullptr;
commandEntry->reason = reason;
}
@@ -3838,6 +3880,14 @@
}
}
+void InputDispatcher::doNotifyFocusChangedLockedInterruptible(
+ CommandEntry* commandEntry) {
+ sp<IBinder> token = commandEntry->token;
+ mLock.unlock();
+ mPolicy->notifyFocusChanged(token);
+ mLock.lock();
+}
+
void InputDispatcher::doNotifyANRLockedInterruptible(
CommandEntry* commandEntry) {
mLock.unlock();
@@ -4343,10 +4393,12 @@
volatile int32_t InputDispatcher::DispatchEntry::sNextSeqAtomic;
InputDispatcher::DispatchEntry::DispatchEntry(EventEntry* eventEntry,
- int32_t targetFlags, float xOffset, float yOffset, float scaleFactor) :
+ int32_t targetFlags, float xOffset, float yOffset, float globalScaleFactor,
+ float windowXScale, float windowYScale) :
seq(nextSeq()),
eventEntry(eventEntry), targetFlags(targetFlags),
- xOffset(xOffset), yOffset(yOffset), scaleFactor(scaleFactor),
+ xOffset(xOffset), yOffset(yOffset), globalScaleFactor(globalScaleFactor),
+ windowXScale(windowXScale), windowYScale(windowYScale),
deliveryTime(0), resolvedAction(0), resolvedFlags(0) {
eventEntry->refCount += 1;
}
@@ -4847,7 +4899,7 @@
void InputDispatcher::TouchState::removeWindowByToken(const sp<IBinder>& token) {
for (size_t i = 0; i < windows.size(); i++) {
- if (windows.itemAt(i).windowHandle->getInputChannel()->getToken() == token) {
+ if (windows.itemAt(i).windowHandle->getToken() == token) {
windows.removeAt(i);
return;
}
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 5016082..73bcc25 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -29,6 +29,7 @@
#include <utils/Looper.h>
#include <utils/BitSet.h>
#include <cutils/atomic.h>
+#include <unordered_map>
#include <stddef.h>
#include <unistd.h>
@@ -159,7 +160,9 @@
// Scaling factor to apply to MotionEvent as it is delivered.
// (ignored for KeyEvents)
- float scaleFactor;
+ float globalScaleFactor;
+ float windowXScale = 1.0f;
+ float windowYScale = 1.0f;
// The subset of pointer ids to include in motion events dispatched to this input target
// if FLAG_SPLIT is set.
@@ -213,6 +216,7 @@
/* Notifies the system that an input channel is unrecoverably broken. */
virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0;
+ virtual void notifyFocusChanged(const sp<IBinder>& token) = 0;
/* Gets the input dispatcher configuration. */
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0;
@@ -561,7 +565,9 @@
int32_t targetFlags;
float xOffset;
float yOffset;
- float scaleFactor;
+ float globalScaleFactor;
+ float windowXScale = 1.0f;
+ float windowYScale = 1.0f;
nsecs_t deliveryTime; // time when the event was actually delivered
// Set to the resolved action and flags when the event is enqueued.
@@ -569,7 +575,8 @@
int32_t resolvedFlags;
DispatchEntry(EventEntry* eventEntry,
- int32_t targetFlags, float xOffset, float yOffset, float scaleFactor);
+ int32_t targetFlags, float xOffset, float yOffset,
+ float globalScaleFactor, float windowXScale, float windowYScale);
~DispatchEntry();
inline bool hasForegroundTarget() const {
@@ -622,6 +629,7 @@
uint32_t seq;
bool handled;
sp<InputChannel> inputChannel;
+ sp<IBinder> token;
};
// Generic queue implementation.
@@ -916,6 +924,13 @@
// All registered connections mapped by channel file descriptor.
KeyedVector<int, sp<Connection> > mConnectionsByFd;
+ struct IBinderHash {
+ std::size_t operator()(const sp<IBinder>& b) const {
+ return std::hash<IBinder *>{}(b.get());
+ }
+ };
+ std::unordered_map<sp<IBinder>, sp<InputChannel>, IBinderHash> mInputChannelsByToken;
+
ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel);
// Input channels that will receive a copy of all input events sent to the provided display.
@@ -979,6 +994,7 @@
// Get window handles by display, return an empty vector if not found.
Vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId) const;
sp<InputWindowHandle> getWindowHandleLocked(const sp<InputChannel>& inputChannel) const;
+ sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const;
bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const;
// Focus tracking for keys, trackball, etc.
@@ -1051,7 +1067,7 @@
nsecs_t mInputTargetWaitStartTime;
nsecs_t mInputTargetWaitTimeoutTime;
bool mInputTargetWaitTimeoutExpired;
- sp<InputApplicationHandle> mInputTargetWaitApplicationHandle;
+ sp<IBinder> mInputTargetWaitApplicationToken;
// Contains the last window which received a hover event.
sp<InputWindowHandle> mLastHoverWindowHandle;
@@ -1143,6 +1159,7 @@
nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled);
void onDispatchCycleBrokenLocked(
nsecs_t currentTime, const sp<Connection>& connection);
+ void onFocusChangedLocked(const sp<InputWindowHandle>& newFocus);
void onANRLocked(
nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle,
@@ -1151,6 +1168,7 @@
// Outbound policy interactions.
void doNotifyConfigurationChangedInterruptible(CommandEntry* commandEntry);
void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry);
+ void doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry);
void doNotifyANRLockedInterruptible(CommandEntry* commandEntry);
void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry);
void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry);
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 388423c..15d8070 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -21,9 +21,13 @@
#include "InputManager.h"
#include "InputReaderFactory.h"
+#include <binder/IPCThreadState.h>
+
#include <log/log.h>
#include <unordered_map>
+#include <private/android_filesystem_config.h>
+
namespace android {
InputManager::InputManager(
@@ -83,20 +87,9 @@
return mDispatcher;
}
-class BinderApplicationHandle : public InputApplicationHandle {
-public:
- BinderApplicationHandle() = default;
-
- bool updateInfo() override {
- return true;
- }
-};
-
class BinderWindowHandle : public InputWindowHandle {
public:
- BinderWindowHandle(const InputWindowInfo& info) :
- InputWindowHandle(new BinderApplicationHandle()) {
-
+ BinderWindowHandle(const InputWindowInfo& info) {
mInfo = info;
}
@@ -118,4 +111,20 @@
}
}
+// Used by tests only.
+void InputManager::registerInputChannel(const sp<InputChannel>& channel) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int uid = ipc->getCallingUid();
+ if (uid != AID_SHELL && uid != AID_ROOT) {
+ ALOGE("Invalid attempt to register input channel over IPC"
+ "from non shell/root entity (PID: %d)", ipc->getCallingPid());
+ return;
+ }
+ mDispatcher->registerInputChannel(channel, false);
+}
+
+void InputManager::unregisterInputChannel(const sp<InputChannel>& channel) {
+ mDispatcher->unregisterInputChannel(channel);
+}
+
} // namespace android
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 1173fa1..8f7551e 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -35,6 +35,7 @@
#include <utils/RefBase.h>
namespace android {
+class InputChannel;
/*
* The input manager is the core of the system event processing.
@@ -91,6 +92,9 @@
virtual void setInputWindows(const Vector<InputWindowInfo>& handles);
+ virtual void registerInputChannel(const sp<InputChannel>& channel);
+ virtual void unregisterInputChannel(const sp<InputChannel>& channel);
+
private:
sp<InputReaderInterface> mReader;
sp<InputReaderThread> mReaderThread;
diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp
index 0e48f24..cbe0190 100644
--- a/services/inputflinger/host/Android.bp
+++ b/services/inputflinger/host/Android.bp
@@ -62,6 +62,4 @@
static_libs: [
"libarect",
],
-
- init_rc: ["inputflinger.rc"],
}
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index 15ca7b3..82ff089 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -40,6 +40,8 @@
virtual status_t dump(int fd, const Vector<String16>& args);
void setInputWindows(const Vector<InputWindowInfo>&) {}
+ void registerInputChannel(const sp<InputChannel>&) {}
+ void unregisterInputChannel(const sp<InputChannel>&) {}
private:
virtual ~InputFlinger();
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index e860db5..26f01b7 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -63,6 +63,9 @@
virtual void notifyInputChannelBroken(const sp<IBinder>&) {
}
+ virtual void notifyFocusChanged(const sp<IBinder>&) {
+ }
+
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
*outConfig = mConfig;
}
@@ -338,7 +341,6 @@
const std::string name, int32_t displayId) :
mDispatcher(dispatcher), mName(name), mDisplayId(displayId) {
InputChannel::openInputChannelPair(name, mServerChannel, mClientChannel);
-
mConsumer = new InputConsumer(mClientChannel);
}
@@ -352,6 +354,7 @@
sp<InputDispatcher> mDispatcher;
sp<InputChannel> mServerChannel, mClientChannel;
+ sp<IBinder> mToken;
InputConsumer *mConsumer;
PreallocatedInputEventFactory mEventFactory;
@@ -366,15 +369,17 @@
FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle,
const sp<InputDispatcher>& dispatcher, const std::string name, int32_t displayId) :
- InputWindowHandle(inputApplicationHandle),
FakeInputReceiver(dispatcher, name, displayId),
mFocused(false) {
mServerChannel->setToken(new BBinder());
mDispatcher->registerInputChannel(mServerChannel, displayId);
+
+ inputApplicationHandle->updateInfo();
+ mInfo.applicationInfo = *inputApplicationHandle->getInfo();
}
virtual bool updateInfo() {
- mInfo.inputChannel = mServerChannel;
+ mInfo.token = mServerChannel->getToken();
mInfo.name = mName;
mInfo.layoutParamsFlags = 0;
mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
@@ -383,7 +388,7 @@
mInfo.frameTop = 0;
mInfo.frameRight = WIDTH;
mInfo.frameBottom = HEIGHT;
- mInfo.scaleFactor = 1.0;
+ mInfo.globalScaleFactor = 1.0;
mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
mInfo.visible = true;
mInfo.canReceiveKeys = true;
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 088c256..1007b3d 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -54,6 +54,7 @@
"libsync",
"libtimestats_proto",
"libui",
+ "libinput",
"libutils",
],
static_libs: [
@@ -183,6 +184,7 @@
"libdisplayservicehidl",
"libhidlbase",
"libhidltransport",
+ "libinput",
"liblayers_proto",
"liblog",
"libsync",
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f3182be..6ac0901 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1057,6 +1057,11 @@
clearSyncPoints();
}
+ if (mCurrentState.inputInfoChanged) {
+ flags |= eInputInfoChanged;
+ mCurrentState.inputInfoChanged = false;
+ }
+
// Commit the transaction
commitTransaction(c);
mCurrentState.callbackHandles = {};
@@ -1928,6 +1933,13 @@
mDrawingParent = mCurrentParent;
}
+void Layer::setInputInfo(const InputWindowInfo& info) {
+ mCurrentState.inputInfo = info;
+ mCurrentState.modified = true;
+ mCurrentState.inputInfoChanged = true;
+ setTransactionFlags(eTransactionNeeded);
+}
+
void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet) {
const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
@@ -2055,6 +2067,30 @@
return mRemovedFromCurrentState;
}
+InputWindowInfo Layer::fillInputInfo(const Rect& screenBounds) {
+ InputWindowInfo info = mDrawingState.inputInfo;
+ info.frameLeft = screenBounds.left + info.surfaceInset;
+ info.frameTop = screenBounds.top + info.surfaceInset;
+ info.frameRight = screenBounds.right - info.surfaceInset;
+ info.frameBottom = screenBounds.bottom - info.surfaceInset;
+
+ ui::Transform t = getTransform();
+ info.windowXScale *= 1.0f / t.sx();
+ info.windowYScale *= 1.0f / t.sy();
+
+ info.touchableRegion.scaleSelf(t.sx(), t.sy());
+
+ info.touchableRegion = info.touchableRegion.translate(
+ screenBounds.left,
+ screenBounds.top);
+ info.visible = isVisible();
+ return info;
+}
+
+bool Layer::hasInput() const {
+ return mDrawingState.inputInfo.token != nullptr;
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index ed51c61..fe8d5a9 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -22,6 +22,7 @@
#include <gui/BufferQueue.h>
#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerState.h>
+#include <input/InputWindow.h>
#include <layerproto/LayerProtoHeader.h>
#include <math/vec4.h>
#include <renderengine/Mesh.h>
@@ -109,6 +110,7 @@
enum { // flags for doTransaction()
eDontUpdateGeometryState = 0x00000001,
eVisibleRegion = 0x00000002,
+ eInputInfoChanged = 0x00000004
};
struct Geometry {
@@ -166,6 +168,9 @@
half4 color;
+ bool inputInfoChanged;
+ InputWindowInfo inputInfo;
+
// The fields below this point are only used by BufferStateLayer
Geometry active;
@@ -708,6 +713,10 @@
bool getPremultipledAlpha() const;
bool mPendingHWCDestroy{false};
+ void setInputInfo(const InputWindowInfo& info);
+
+ InputWindowInfo fillInputInfo(const Rect& screenBounds);
+ bool hasInput() const;
protected:
// -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 8e694fd..1db8791 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -37,6 +37,8 @@
#include <dvr/vr_flinger.h>
+#include <input/IInputFlinger.h>
+
#include <ui/ColorSpace.h>
#include <ui/DebugUtils.h>
#include <ui/DisplayInfo.h>
@@ -554,6 +556,13 @@
if (window != 0) {
window->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
}
+ sp<IBinder> input(defaultServiceManager()->getService(
+ String16("inputflinger")));
+ if (input == nullptr) {
+ ALOGE("Failed to link to input service");
+ } else {
+ mInputFlinger = interface_cast<IInputFlinger>(input);
+ }
if (mVrFlinger) {
mVrFlinger->OnBootFinished();
@@ -2573,6 +2582,7 @@
* (perform the transaction for each of them if needed)
*/
+ bool inputChanged = false;
if (transactionFlags & eTraversalNeeded) {
mCurrentState.traverseInZOrder([&](Layer* layer) {
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
@@ -2581,6 +2591,10 @@
const uint32_t flags = layer->doTransaction(0);
if (flags & Layer::eVisibleRegion)
mVisibleRegionsDirty = true;
+
+ if (flags & Layer::eInputInfoChanged) {
+ inputChanged = true;
+ }
});
}
@@ -2690,9 +2704,26 @@
commitTransaction();
+ if ((inputChanged || mVisibleRegionsDirty) && mInputFlinger) {
+ updateInputWindows();
+ }
+
updateCursorAsync();
}
+void SurfaceFlinger::updateInputWindows() {
+ ATRACE_CALL();
+
+ Vector<InputWindowInfo> inputHandles;
+
+ mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
+ if (layer->hasInput()) {
+ inputHandles.add(layer->fillInputInfo(layer->computeScreenBounds()));
+ }
+ });
+ mInputFlinger->setInputWindows(inputHandles);
+}
+
void SurfaceFlinger::updateCursorAsync()
{
for (const auto& [token, display] : mDisplays) {
@@ -2800,6 +2831,7 @@
if (CC_LIKELY(layer->isVisible())) {
const bool translucent = !layer->isOpaque(s);
Rect bounds(layer->computeScreenBounds());
+
visibleRegion.set(bounds);
ui::Transform tr = layer->getTransform();
if (!visibleRegion.isEmpty()) {
@@ -3615,7 +3647,10 @@
if (what & layer_state_t::eSidebandStreamChanged) {
if (layer->setSidebandStream(s.sidebandStream)) flags |= eTraversalNeeded;
}
-
+ if (what & layer_state_t::eInputInfoChanged) {
+ layer->setInputInfo(s.inputInfo);
+ flags |= eTraversalNeeded;
+ }
std::vector<sp<CallbackHandle>> callbackHandles;
if ((what & layer_state_t::eListenerCallbacksChanged) && (!s.listenerCallbacks.empty())) {
mTransactionCompletedThread.run();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f98dddf..4a14de7 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -98,6 +98,7 @@
class EventThread;
class IGraphicBufferConsumer;
class IGraphicBufferProducer;
+class IInputFlinger;
class InjectVSyncSource;
class Layer;
class Surface;
@@ -531,6 +532,7 @@
void handleTransaction(uint32_t transactionFlags);
void handleTransactionLocked(uint32_t transactionFlags);
+ void updateInputWindows();
void updateCursorAsync();
/* handlePageFlip - latch a new buffer if available and compute the dirty
@@ -986,6 +988,8 @@
std::unique_ptr<Scheduler> mScheduler;
sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
+
+ sp<IInputFlinger> mInputFlinger;
};
}; // namespace android