Merge "Add Flags<F>::Iterator."
diff --git a/cmds/idlcli/vibrator/CommandCompose.cpp b/cmds/idlcli/vibrator/CommandCompose.cpp
index 97c057f..eb9008b 100644
--- a/cmds/idlcli/vibrator/CommandCompose.cpp
+++ b/cmds/idlcli/vibrator/CommandCompose.cpp
@@ -37,7 +37,7 @@
{"-b", {"Block for duration of vibration."}},
{"<delay>", {"In milliseconds"}},
{"<primitive>", {"Primitive ID."}},
- {"<scale>", {"0.0 (exclusive) - 1.0 (inclusive)."}},
+ {"<scale>", {"0.0 (inclusive) - 1.0 (inclusive)."}},
{"...", {"May repeat multiple times."}},
};
return details;
@@ -72,7 +72,7 @@
return USAGE;
}
if (auto scale = args.pop<decltype(effect.scale)>();
- scale && *scale > 0.0 && scale <= 1.0) {
+ scale && *scale >= 0.0 && scale <= 1.0) {
effect.scale = *scale;
std::cout << "Scale: " << effect.scale << std::endl;
} else {
diff --git a/headers/media_plugin/media/openmax/OMX_VideoExt.h b/headers/media_plugin/media/openmax/OMX_VideoExt.h
index dc37bbd..e65b224 100644
--- a/headers/media_plugin/media/openmax/OMX_VideoExt.h
+++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h
@@ -321,6 +321,46 @@
OMX_VIDEO_DolbyVisionLevelmax = 0x7FFFFFFF
} OMX_VIDEO_DOLBYVISIONLEVELTYPE;
+/** AV1 Profile enum type */
+typedef enum OMX_VIDEO_AV1PROFILETYPE {
+ OMX_VIDEO_AV1ProfileMain8 = 0x00000001,
+ OMX_VIDEO_AV1ProfileMain10 = 0x00000002,
+ OMX_VIDEO_AV1ProfileMain10HDR10 = 0x00001000,
+ OMX_VIDEO_AV1ProfileMain10HDR10Plus = 0x00002000,
+ OMX_VIDEO_AV1ProfileUnknown = 0x6EFFFFFF,
+ OMX_VIDEO_AV1ProfileMax = 0x7FFFFFFF
+} OMX_VIDEO_AV1PROFILETYPE;
+
+/** AV1 Level enum type */
+typedef enum OMX_VIDEO_AV1LEVELTYPE {
+ OMX_VIDEO_AV1Level2 = 0x1,
+ OMX_VIDEO_AV1Level21 = 0x2,
+ OMX_VIDEO_AV1Level22 = 0x4,
+ OMX_VIDEO_AV1Level23 = 0x8,
+ OMX_VIDEO_AV1Level3 = 0x10,
+ OMX_VIDEO_AV1Level31 = 0x20,
+ OMX_VIDEO_AV1Level32 = 0x40,
+ OMX_VIDEO_AV1Level33 = 0x80,
+ OMX_VIDEO_AV1Level4 = 0x100,
+ OMX_VIDEO_AV1Level41 = 0x200,
+ OMX_VIDEO_AV1Level42 = 0x400,
+ OMX_VIDEO_AV1Level43 = 0x800,
+ OMX_VIDEO_AV1Level5 = 0x1000,
+ OMX_VIDEO_AV1Level51 = 0x2000,
+ OMX_VIDEO_AV1Level52 = 0x4000,
+ OMX_VIDEO_AV1Level53 = 0x8000,
+ OMX_VIDEO_AV1Level6 = 0x10000,
+ OMX_VIDEO_AV1Level61 = 0x20000,
+ OMX_VIDEO_AV1Level62 = 0x40000,
+ OMX_VIDEO_AV1Level63 = 0x80000,
+ OMX_VIDEO_AV1Level7 = 0x100000,
+ OMX_VIDEO_AV1Level71 = 0x200000,
+ OMX_VIDEO_AV1Level72 = 0x400000,
+ OMX_VIDEO_AV1Level73 = 0x800000,
+ OMX_VIDEO_AV1LevelUnknown = 0x6EFFFFFF,
+ OMX_VIDEO_AV1LevelMax = 0x7FFFFFFF
+} OMX_VIDEO_AV1LEVELTYPE;
+
/**
* Structure for configuring video compression intra refresh period
*
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index bdf11e4..e9f559c 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -130,6 +130,13 @@
* This api is thread-safe. Any thread is allowed to register a new refresh
* rate callback for the choreographer instance.
*
+ * Note that in API level 30, this api is not guaranteed to be atomic with
+ * DisplayManager. That is, calling Display#getRefreshRate very soon after
+ * a refresh rate callback is invoked may return a stale refresh rate. If any
+ * Display properties would be required by this callback, then it is recommended
+ * to listen directly to DisplayManager.DisplayListener#onDisplayChanged events
+ * instead.
+ *
* Available since API level 30.
*/
void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
diff --git a/include/input/Input.h b/include/input/Input.h
index 40d655f..9525bcb 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -87,6 +87,13 @@
constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS =
AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
+/**
+ * This flag indicates that the point up event has been canceled.
+ * Typically this is used for palm event when the user has accidental touches.
+ * TODO: Adjust flag to public api
+ */
+constexpr int32_t AMOTION_EVENT_FLAG_CANCELED = 0x20;
+
enum {
/* Used when a motion event is not associated with any display.
* Typically used for non-pointer events. */
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 09cebef..24f8e77 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -183,18 +183,6 @@
}
};
-struct InputChannelInfo : public Parcelable {
- std::string mName;
- android::base::unique_fd mFd;
- sp<IBinder> mToken;
-
- InputChannelInfo() = default;
- InputChannelInfo(const std::string& name, android::base::unique_fd fd, sp<IBinder> token)
- : mName(name), mFd(std::move(fd)), mToken(token){};
- status_t readFromParcel(const android::Parcel* parcel) override;
- status_t writeToParcel(android::Parcel* parcel) const override;
-};
-
/*
* An input channel consists of a local unix domain socket used to send and receive
* input messages across processes. Each channel has a descriptive name for debugging purposes.
@@ -203,14 +191,15 @@
*
* The input channel is closed when all references to it are released.
*/
-class InputChannel : public RefBase {
+class InputChannel : public Parcelable {
public:
- InputChannel();
+ static std::unique_ptr<InputChannel> create(const std::string& name,
+ android::base::unique_fd fd, sp<IBinder> token);
+ InputChannel() = default;
+ InputChannel(const InputChannel& other)
+ : mName(other.mName), mFd(::dup(other.mFd)), mToken(other.mToken){};
+ InputChannel(const std::string name, android::base::unique_fd fd, sp<IBinder> token);
virtual ~InputChannel();
-
- static sp<InputChannel> create(const std::string& name, android::base::unique_fd fd,
- sp<IBinder> token);
-
/**
* Create a pair of input channels.
* The two returned input channels are equivalent, and are labeled as "server" and "client"
@@ -219,12 +208,12 @@
* Return OK on success.
*/
static status_t openInputChannelPair(const std::string& name,
- sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel);
+ std::unique_ptr<InputChannel>& outServerChannel,
+ std::unique_ptr<InputChannel>& outClientChannel);
- inline std::string getName() const { return mInfo.mName; }
- inline int getFd() const { return mInfo.mFd.get(); }
- inline sp<IBinder> getToken() const { return mInfo.mToken; }
- inline InputChannelInfo& getInfo() { return mInfo; }
+ inline std::string getName() const { return mName; }
+ inline const android::base::unique_fd& getFd() const { return mFd; }
+ inline sp<IBinder> getToken() const { return mToken; }
/* Send a message to the other endpoint.
*
@@ -252,11 +241,10 @@
status_t receiveMessage(InputMessage* msg);
/* Return a new object that has a duplicate of this channel's fd. */
- sp<InputChannel> dup() const;
+ std::unique_ptr<InputChannel> dup() const;
- status_t readFromParcel(const android::Parcel* parcel);
-
- status_t writeToParcel(android::Parcel* parcel) const;
+ status_t readFromParcel(const android::Parcel* parcel) override;
+ status_t writeToParcel(android::Parcel* parcel) const override;
/**
* The connection token is used to identify the input connection, i.e.
@@ -273,22 +261,23 @@
sp<IBinder> getConnectionToken() const;
bool operator==(const InputChannel& inputChannel) const {
- struct stat lhsInfo, rhsInfo;
- if (fstat(mInfo.mFd.get(), &lhsInfo) != 0) {
+ struct stat lhs, rhs;
+ if (fstat(mFd.get(), &lhs) != 0) {
return false;
}
- if (fstat(inputChannel.getFd(), &rhsInfo) != 0) {
+ if (fstat(inputChannel.getFd(), &rhs) != 0) {
return false;
}
// If file descriptors are pointing to same inode they are duplicated fds.
- return inputChannel.getName() == getName() &&
- inputChannel.getConnectionToken() == mInfo.mToken &&
- lhsInfo.st_ino == rhsInfo.st_ino;
+ return inputChannel.getName() == getName() && inputChannel.getConnectionToken() == mToken &&
+ lhs.st_ino == rhs.st_ino;
}
private:
- InputChannel(const std::string& name, android::base::unique_fd fd, sp<IBinder> token);
- InputChannelInfo mInfo;
+ std::string mName;
+ android::base::unique_fd mFd;
+
+ sp<IBinder> mToken;
};
/*
@@ -297,13 +286,13 @@
class InputPublisher {
public:
/* Creates a publisher associated with an input channel. */
- explicit InputPublisher(const sp<InputChannel>& channel);
+ explicit InputPublisher(const std::shared_ptr<InputChannel>& channel);
/* Destroys the publisher and releases its input channel. */
~InputPublisher();
/* Gets the underlying input channel. */
- inline sp<InputChannel> getChannel() { return mChannel; }
+ inline std::shared_ptr<InputChannel> getChannel() { return mChannel; }
/* Publishes a key event to the input channel.
*
@@ -360,7 +349,7 @@
status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled);
private:
- sp<InputChannel> mChannel;
+ std::shared_ptr<InputChannel> mChannel;
};
/*
@@ -369,13 +358,13 @@
class InputConsumer {
public:
/* Creates a consumer associated with an input channel. */
- explicit InputConsumer(const sp<InputChannel>& channel);
+ explicit InputConsumer(const std::shared_ptr<InputChannel>& channel);
/* Destroys the consumer and releases its input channel. */
~InputConsumer();
/* Gets the underlying input channel. */
- inline sp<InputChannel> getChannel() { return mChannel; }
+ inline std::shared_ptr<InputChannel> getChannel() { return mChannel; }
/* Consumes an input event from the input channel and copies its contents into
* an InputEvent object created using the specified factory.
@@ -451,8 +440,7 @@
// True if touch resampling is enabled.
const bool mResampleTouch;
- // The input channel.
- sp<InputChannel> mChannel;
+ std::shared_ptr<InputChannel> mChannel;
// The current input message.
InputMessage mMsg;
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 383d591..cca8ddd 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -68,11 +68,12 @@
public:
InputSurface(const sp<SurfaceControl> &sc, int width, int height) {
mSurfaceControl = sc;
-
- InputChannel::openInputChannelPair("testchannels", mServerChannel, mClientChannel);
+ std::unique_ptr<InputChannel> clientChannel;
+ InputChannel::openInputChannelPair("testchannels", mServerChannel, clientChannel);
+ mClientChannel = std::move(clientChannel);
mInputFlinger = getInputFlinger();
- mInputFlinger->registerInputChannel(mServerChannel->getInfo());
+ mInputFlinger->registerInputChannel(*mServerChannel);
populateInputInfo(width, height);
@@ -154,7 +155,7 @@
EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS);
}
- ~InputSurface() { mInputFlinger->unregisterInputChannel(mServerChannel->getInfo()); }
+ ~InputSurface() { mInputFlinger->unregisterInputChannel(*mServerChannel); }
void doTransaction(std::function<void(SurfaceComposerClient::Transaction&,
const sp<SurfaceControl>&)> transactionBody) {
@@ -211,7 +212,8 @@
}
public:
sp<SurfaceControl> mSurfaceControl;
- sp<InputChannel> mServerChannel, mClientChannel;
+ std::unique_ptr<InputChannel> mServerChannel;
+ std::shared_ptr<InputChannel> mClientChannel;
sp<IInputFlinger> mInputFlinger;
InputWindowInfo mInputInfo;
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 60ad578..8dcc415 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -241,65 +241,42 @@
}
}
-// --- InputChannelInfo ---
-
-status_t InputChannelInfo::writeToParcel(android::Parcel* parcel) const {
- if (parcel == nullptr) {
- ALOGE("%s: Null parcel", __func__);
- return BAD_VALUE;
- }
- status_t status = parcel->writeStrongBinder(mToken)
- ?: parcel->writeUtf8AsUtf16(mName) ?: parcel->writeUniqueFileDescriptor(mFd);
- return status;
-}
-
-status_t InputChannelInfo::readFromParcel(const android::Parcel* parcel) {
- if (parcel == nullptr) {
- ALOGE("%s: Null parcel", __func__);
- return BAD_VALUE;
- }
- mToken = parcel->readStrongBinder();
- status_t status = parcel->readUtf8FromUtf16(&mName) ?: parcel->readUniqueFileDescriptor(&mFd);
- return status;
-}
-
// --- InputChannel ---
-sp<InputChannel> InputChannel::create(const std::string& name, android::base::unique_fd fd,
- sp<IBinder> token) {
+std::unique_ptr<InputChannel> InputChannel::create(const std::string& name,
+ android::base::unique_fd fd, sp<IBinder> token) {
const int result = fcntl(fd, F_SETFL, O_NONBLOCK);
if (result != 0) {
LOG_ALWAYS_FATAL("channel '%s' ~ Could not make socket non-blocking: %s", name.c_str(),
strerror(errno));
return nullptr;
}
- return new InputChannel(name, std::move(fd), token);
+ // using 'new' to access a non-public constructor
+ return std::unique_ptr<InputChannel>(new InputChannel(name, std::move(fd), token));
}
-InputChannel::InputChannel(const std::string& name, android::base::unique_fd fd, sp<IBinder> token)
- : mInfo(name, std::move(fd), token) {
+InputChannel::InputChannel(const std::string name, android::base::unique_fd fd, sp<IBinder> token)
+ : mName(std::move(name)), mFd(std::move(fd)), mToken(std::move(token)) {
if (DEBUG_CHANNEL_LIFECYCLE) {
- ALOGD("Input channel constructed: name='%s', fd=%d", mInfo.mName.c_str(), mInfo.mFd.get());
+ ALOGD("Input channel constructed: name='%s', fd=%d", getName().c_str(), getFd().get());
}
}
-InputChannel::InputChannel() {}
-
InputChannel::~InputChannel() {
if (DEBUG_CHANNEL_LIFECYCLE) {
- ALOGD("Input channel destroyed: name='%s', fd=%d", getName().c_str(), getFd());
+ ALOGD("Input channel destroyed: name='%s', fd=%d", getName().c_str(), getFd().get());
}
}
status_t InputChannel::openInputChannelPair(const std::string& name,
- sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
+ std::unique_ptr<InputChannel>& outServerChannel,
+ std::unique_ptr<InputChannel>& outClientChannel) {
int sockets[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
status_t result = -errno;
- ALOGE("channel '%s' ~ Could not create socket pair. errno=%d",
- name.c_str(), errno);
- outServerChannel.clear();
- outClientChannel.clear();
+ ALOGE("channel '%s' ~ Could not create socket pair. errno=%d", name.c_str(), errno);
+ outServerChannel.reset();
+ outClientChannel.reset();
return result;
}
@@ -399,10 +376,10 @@
return OK;
}
-sp<InputChannel> InputChannel::dup() const {
+std::unique_ptr<InputChannel> InputChannel::dup() const {
android::base::unique_fd newFd(::dup(getFd()));
if (!newFd.ok()) {
- ALOGE("Could not duplicate fd %i for channel %s: %s", getFd(), getName().c_str(),
+ ALOGE("Could not duplicate fd %i for channel %s: %s", getFd().get(), getName().c_str(),
strerror(errno));
const bool hitFdLimit = errno == EMFILE || errno == ENFILE;
// If this process is out of file descriptors, then throwing that might end up exploding
@@ -417,22 +394,30 @@
}
status_t InputChannel::writeToParcel(android::Parcel* parcel) const {
- return mInfo.writeToParcel(parcel);
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __func__);
+ return BAD_VALUE;
+ }
+ return parcel->writeStrongBinder(mToken)
+ ?: parcel->writeUtf8AsUtf16(mName) ?: parcel->writeUniqueFileDescriptor(mFd);
}
status_t InputChannel::readFromParcel(const android::Parcel* parcel) {
- return mInfo.readFromParcel(parcel);
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __func__);
+ return BAD_VALUE;
+ }
+ mToken = parcel->readStrongBinder();
+ return parcel->readUtf8FromUtf16(&mName) ?: parcel->readUniqueFileDescriptor(&mFd);
}
sp<IBinder> InputChannel::getConnectionToken() const {
- return mInfo.mToken;
+ return mToken;
}
// --- InputPublisher ---
-InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
- mChannel(channel) {
-}
+InputPublisher::InputPublisher(const std::shared_ptr<InputChannel>& channel) : mChannel(channel) {}
InputPublisher::~InputPublisher() {
}
@@ -596,10 +581,8 @@
// --- InputConsumer ---
-InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
- mResampleTouch(isTouchResamplingEnabled()),
- mChannel(channel), mMsgDeferred(false) {
-}
+InputConsumer::InputConsumer(const std::shared_ptr<InputChannel>& channel)
+ : mResampleTouch(isTouchResamplingEnabled()), mChannel(channel), mMsgDeferred(false) {}
InputConsumer::~InputConsumer() {
}
diff --git a/libs/input/android/InputChannelInfo.aidl b/libs/input/android/InputChannel.aidl
similarity index 91%
rename from libs/input/android/InputChannelInfo.aidl
rename to libs/input/android/InputChannel.aidl
index 2e83b96..c2d1112 100644
--- a/libs/input/android/InputChannelInfo.aidl
+++ b/libs/input/android/InputChannel.aidl
@@ -17,4 +17,4 @@
package android;
-parcelable InputChannelInfo cpp_header "input/InputTransport.h";
+parcelable InputChannel cpp_header "input/InputTransport.h";
diff --git a/libs/input/android/os/IInputFlinger.aidl b/libs/input/android/os/IInputFlinger.aidl
index 8b7c4fc..44bb66d 100644
--- a/libs/input/android/os/IInputFlinger.aidl
+++ b/libs/input/android/os/IInputFlinger.aidl
@@ -16,7 +16,7 @@
package android.os;
-import android.InputChannelInfo;
+import android.InputChannel;
import android.InputWindowInfo;
import android.os.ISetInputWindowsListener;
@@ -29,6 +29,6 @@
// shouldn't be a concern.
oneway void setInputWindows(in InputWindowInfo[] inputHandles,
in @nullable ISetInputWindowsListener setInputWindowsListener);
- void registerInputChannel(in InputChannelInfo info);
- void unregisterInputChannel(in InputChannelInfo info);
+ void registerInputChannel(in InputChannel channel);
+ void unregisterInputChannel(in InputChannel channel);
}
diff --git a/libs/input/tests/InputChannel_test.cpp b/libs/input/tests/InputChannel_test.cpp
index 4187ca9..0661261 100644
--- a/libs/input/tests/InputChannel_test.cpp
+++ b/libs/input/tests/InputChannel_test.cpp
@@ -33,9 +33,6 @@
namespace android {
class InputChannelTest : public testing::Test {
-protected:
- virtual void SetUp() { }
- virtual void TearDown() { }
};
@@ -47,7 +44,7 @@
android::base::unique_fd sendFd(pipe.sendFd);
- sp<InputChannel> inputChannel =
+ std::unique_ptr<InputChannel> inputChannel =
InputChannel::create("channel name", std::move(sendFd), new BBinder());
EXPECT_NE(inputChannel, nullptr) << "channel should be successfully created";
@@ -62,14 +59,14 @@
TEST_F(InputChannelTest, SetAndGetToken) {
Pipe pipe;
sp<IBinder> token = new BBinder();
- sp<InputChannel> channel =
+ std::unique_ptr<InputChannel> channel =
InputChannel::create("test channel", android::base::unique_fd(pipe.sendFd), token);
EXPECT_EQ(token, channel->getConnectionToken());
}
TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) {
- sp<InputChannel> serverChannel, clientChannel;
+ std::unique_ptr<InputChannel> serverChannel, clientChannel;
status_t result = InputChannel::openInputChannelPair("channel name",
serverChannel, clientChannel);
@@ -120,7 +117,7 @@
}
TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) {
- sp<InputChannel> serverChannel, clientChannel;
+ std::unique_ptr<InputChannel> serverChannel, clientChannel;
status_t result = InputChannel::openInputChannelPair("channel name",
serverChannel, clientChannel);
@@ -134,7 +131,7 @@
}
TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) {
- sp<InputChannel> serverChannel, clientChannel;
+ std::unique_ptr<InputChannel> serverChannel, clientChannel;
status_t result = InputChannel::openInputChannelPair("channel name",
serverChannel, clientChannel);
@@ -142,7 +139,7 @@
ASSERT_EQ(OK, result)
<< "should have successfully opened a channel pair";
- serverChannel.clear(); // close server channel
+ serverChannel.reset(); // close server channel
InputMessage msg;
EXPECT_EQ(DEAD_OBJECT, clientChannel->receiveMessage(&msg))
@@ -150,7 +147,7 @@
}
TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) {
- sp<InputChannel> serverChannel, clientChannel;
+ std::unique_ptr<InputChannel> serverChannel, clientChannel;
status_t result = InputChannel::openInputChannelPair("channel name",
serverChannel, clientChannel);
@@ -158,7 +155,7 @@
ASSERT_EQ(OK, result)
<< "should have successfully opened a channel pair";
- serverChannel.clear(); // close server channel
+ serverChannel.reset(); // close server channel
InputMessage msg;
msg.header.type = InputMessage::Type::KEY;
@@ -167,7 +164,7 @@
}
TEST_F(InputChannelTest, SendAndReceive_MotionClassification) {
- sp<InputChannel> serverChannel, clientChannel;
+ std::unique_ptr<InputChannel> serverChannel, clientChannel;
status_t result = InputChannel::openInputChannelPair("channel name",
serverChannel, clientChannel);
ASSERT_EQ(OK, result)
@@ -199,7 +196,7 @@
}
TEST_F(InputChannelTest, InputChannelParcelAndUnparcel) {
- sp<InputChannel> serverChannel, clientChannel;
+ std::unique_ptr<InputChannel> serverChannel, clientChannel;
status_t result =
InputChannel::openInputChannelPair("channel parceling", serverChannel, clientChannel);
@@ -218,14 +215,14 @@
}
TEST_F(InputChannelTest, DuplicateChannelAndAssertEqual) {
- sp<InputChannel> serverChannel, clientChannel;
+ std::unique_ptr<InputChannel> serverChannel, clientChannel;
status_t result =
InputChannel::openInputChannelPair("channel dup", serverChannel, clientChannel);
ASSERT_EQ(OK, result) << "should have successfully opened a channel pair";
- sp<InputChannel> dupChan = serverChannel->dup();
+ std::unique_ptr<InputChannel> dupChan = serverChannel->dup();
EXPECT_EQ(*serverChannel == *dupChan, true) << "inputchannel should be equal after duplication";
}
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 8e2eec8..5ddc858 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -30,33 +30,21 @@
class InputPublisherAndConsumerTest : public testing::Test {
protected:
- sp<InputChannel> serverChannel, clientChannel;
- InputPublisher* mPublisher;
- InputConsumer* mConsumer;
+ std::shared_ptr<InputChannel> mServerChannel, mClientChannel;
+ std::unique_ptr<InputPublisher> mPublisher;
+ std::unique_ptr<InputConsumer> mConsumer;
PreallocatedInputEventFactory mEventFactory;
- virtual void SetUp() {
+ void SetUp() override {
+ std::unique_ptr<InputChannel> serverChannel, clientChannel;
status_t result = InputChannel::openInputChannelPair("channel name",
serverChannel, clientChannel);
ASSERT_EQ(OK, result);
+ mServerChannel = std::move(serverChannel);
+ mClientChannel = std::move(clientChannel);
- mPublisher = new InputPublisher(serverChannel);
- mConsumer = new InputConsumer(clientChannel);
- }
-
- virtual void TearDown() {
- if (mPublisher) {
- delete mPublisher;
- mPublisher = nullptr;
- }
-
- if (mConsumer) {
- delete mConsumer;
- mConsumer = nullptr;
- }
-
- serverChannel.clear();
- clientChannel.clear();
+ mPublisher = std::make_unique<InputPublisher>(mServerChannel);
+ mConsumer = std::make_unique<InputConsumer>(mClientChannel);
}
void PublishAndConsumeKeyEvent();
@@ -65,8 +53,8 @@
};
TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) {
- EXPECT_EQ(serverChannel.get(), mPublisher->getChannel().get());
- EXPECT_EQ(clientChannel.get(), mConsumer->getChannel().get());
+ EXPECT_EQ(mServerChannel.get(), mPublisher->getChannel().get());
+ EXPECT_EQ(mClientChannel.get(), mConsumer->getChannel().get());
}
void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 5930f0a..d1a3e9a 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -100,6 +100,7 @@
"InputListener.cpp",
"InputReaderBase.cpp",
"InputThread.cpp",
+ "VibrationElement.cpp"
],
}
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index c5f60ad..088c6f1 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -119,7 +119,7 @@
}
// Used by tests only.
-binder::Status InputManager::registerInputChannel(const InputChannelInfo& info) {
+binder::Status InputManager::registerInputChannel(const InputChannel& channel) {
IPCThreadState* ipc = IPCThreadState::self();
const int uid = ipc->getCallingUid();
if (uid != AID_SHELL && uid != AID_ROOT) {
@@ -127,15 +127,12 @@
"from non shell/root entity (PID: %d)", ipc->getCallingPid());
return binder::Status::ok();
}
- android::base::unique_fd newFd(::dup(info.mFd));
- sp<InputChannel> channel = InputChannel::create(info.mName, std::move(newFd), info.mToken);
- mDispatcher->registerInputChannel(channel);
+
+ mDispatcher->registerInputChannel(channel.dup());
return binder::Status::ok();
}
-binder::Status InputManager::unregisterInputChannel(const InputChannelInfo& info) {
- android::base::unique_fd newFd(::dup(info.mFd));
- sp<InputChannel> channel = InputChannel::create(info.mName, std::move(newFd), info.mToken);
+binder::Status InputManager::unregisterInputChannel(const InputChannel& channel) {
mDispatcher->unregisterInputChannel(channel);
return binder::Status::ok();
}
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 4993b54..0503e81 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -108,8 +108,8 @@
const std::vector<InputWindowInfo>& handles,
const sp<ISetInputWindowsListener>& setInputWindowsListener) override;
- binder::Status registerInputChannel(const InputChannelInfo& info) override;
- binder::Status unregisterInputChannel(const InputChannelInfo& info) override;
+ binder::Status registerInputChannel(const InputChannel& channel) override;
+ binder::Status unregisterInputChannel(const InputChannel& channel) override;
private:
sp<InputReaderInterface> mReader;
diff --git a/services/inputflinger/VibrationElement.cpp b/services/inputflinger/VibrationElement.cpp
new file mode 100644
index 0000000..a69f5d0
--- /dev/null
+++ b/services/inputflinger/VibrationElement.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 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 "VibrationElement.h"
+
+#include <android-base/stringprintf.h>
+
+#include <algorithm>
+#include <cinttypes>
+
+using android::base::StringPrintf;
+
+namespace android {
+
+// The sentinel to use the default amplitude
+static const int DEFAULT_AMPLITUDE = -1;
+
+// The vibration magnitude for the "DEFAULT_AMPLITUDE" magnitude constant.
+static const uint16_t DEFAULT_MAGNITUDE = 0xc000;
+
+void VibrationElement::dump(std::string& dump) const {
+ dump += StringPrintf("[duration=%lldms, channels=[", duration.count());
+
+ if (channels.size()) {
+ dump += std::to_string(channels[0]);
+ std::for_each(channels.begin() + 1, channels.end(), [&dump](int channel) {
+ dump += ", ";
+ dump += std::to_string(channel);
+ });
+ }
+ dump += "]]";
+}
+
+uint16_t VibrationElement::getChannel(int id) const {
+ if (id >= (int)channels.size()) {
+ return 0;
+ }
+
+ // android framework uses DEFAULT_AMPLITUDE to signal that the vibration
+ // should use some built-in default value, denoted here as DEFAULT_MAGNITUDE
+ if (channels[id] == DEFAULT_AMPLITUDE) {
+ return DEFAULT_MAGNITUDE;
+ }
+
+ // convert range [0,255] to [0,65535] (android framework to linux ff ranges)
+ return ((uint16_t)channels[id]) << 8;
+}
+
+bool VibrationElement::isOn() const {
+ return std::any_of(channels.begin(), channels.end(),
+ [](uint16_t channel) { return channel != 0; });
+}
+
+} // namespace android
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index a15b7b2..1914a38 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -128,14 +128,17 @@
protected:
explicit FakeInputReceiver(const sp<InputDispatcher>& dispatcher, const std::string name)
: mDispatcher(dispatcher) {
- InputChannel::openInputChannelPair(name, mServerChannel, mClientChannel);
+ std::unique_ptr<InputChannel> serverChannel, clientChannel;
+ InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
+ mServerChannel = std::move(serverChannel);
+ mClientChannel = std::move(clientChannel);
mConsumer = std::make_unique<InputConsumer>(mClientChannel);
}
virtual ~FakeInputReceiver() {}
sp<InputDispatcher> mDispatcher;
- sp<InputChannel> mServerChannel, mClientChannel;
+ std::shared_ptr<InputChannel> mServerChannel, mClientChannel;
std::unique_ptr<InputConsumer> mConsumer;
PreallocatedInputEventFactory mEventFactory;
};
diff --git a/services/inputflinger/dispatcher/Connection.cpp b/services/inputflinger/dispatcher/Connection.cpp
index f5ea563..cee9c39 100644
--- a/services/inputflinger/dispatcher/Connection.cpp
+++ b/services/inputflinger/dispatcher/Connection.cpp
@@ -20,7 +20,7 @@
namespace android::inputdispatcher {
-Connection::Connection(const sp<InputChannel>& inputChannel, bool monitor,
+Connection::Connection(const std::shared_ptr<InputChannel>& inputChannel, bool monitor,
const IdGenerator& idGenerator)
: status(STATUS_NORMAL),
inputChannel(inputChannel),
diff --git a/services/inputflinger/dispatcher/Connection.h b/services/inputflinger/dispatcher/Connection.h
index 3b33f29..c4262ad 100644
--- a/services/inputflinger/dispatcher/Connection.h
+++ b/services/inputflinger/dispatcher/Connection.h
@@ -42,7 +42,7 @@
};
Status status;
- sp<InputChannel> inputChannel; // never null
+ std::shared_ptr<InputChannel> inputChannel; // never null
bool monitor;
InputPublisher inputPublisher;
InputState inputState;
@@ -59,7 +59,8 @@
// yet received a "finished" response from the application.
std::deque<DispatchEntry*> waitQueue;
- Connection(const sp<InputChannel>& inputChannel, bool monitor, const IdGenerator& idGenerator);
+ Connection(const std::shared_ptr<InputChannel>& inputChannel, bool monitor,
+ const IdGenerator& idGenerator);
inline const std::string getInputChannelName() const { return inputChannel->getName(); }
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 6b7697d..4147e41 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -262,7 +262,7 @@
int32_t userActivityEventType;
uint32_t seq;
bool handled;
- sp<InputChannel> inputChannel;
+ std::shared_ptr<InputChannel> inputChannel;
sp<IBinder> oldToken;
sp<IBinder> newToken;
};
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 3bdbcce..da09898 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -433,7 +433,7 @@
while (!mConnectionsByFd.empty()) {
sp<Connection> connection = mConnectionsByFd.begin()->second;
- unregisterInputChannel(connection->inputChannel);
+ unregisterInputChannel(*connection->inputChannel);
}
}
@@ -1105,7 +1105,7 @@
}
void InputDispatcher::dispatchFocusLocked(nsecs_t currentTime, FocusEntry* entry) {
- sp<InputChannel> channel = getInputChannelLocked(entry->connectionToken);
+ std::shared_ptr<InputChannel> channel = getInputChannelLocked(entry->connectionToken);
if (channel == nullptr) {
return; // Window has gone away
}
@@ -2029,7 +2029,8 @@
if (it == inputTargets.end()) {
InputTarget inputTarget;
- sp<InputChannel> inputChannel = getInputChannelLocked(windowHandle->getToken());
+ std::shared_ptr<InputChannel> inputChannel =
+ getInputChannelLocked(windowHandle->getToken());
if (inputChannel == nullptr) {
ALOGW("Window %s already unregistered input channel", windowHandle->getName().c_str());
return;
@@ -2844,7 +2845,7 @@
}
// Unregister the channel.
- d->unregisterInputChannelLocked(connection->inputChannel, notify);
+ d->unregisterInputChannelLocked(*connection->inputChannel, notify);
return 0; // remove the callback
} // release lock
}
@@ -2874,7 +2875,7 @@
}
void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked(
- const sp<InputChannel>& channel, const CancelationOptions& options) {
+ const std::shared_ptr<InputChannel>& channel, const CancelationOptions& options) {
sp<Connection> connection = getConnectionLocked(channel->getConnectionToken());
if (connection == nullptr) {
return;
@@ -3690,7 +3691,8 @@
return false;
}
-sp<InputChannel> InputDispatcher::getInputChannelLocked(const sp<IBinder>& token) const {
+std::shared_ptr<InputChannel> InputDispatcher::getInputChannelLocked(
+ const sp<IBinder>& token) const {
size_t count = mInputChannelsByToken.count(token);
if (count == 0) {
return nullptr;
@@ -3815,7 +3817,7 @@
ALOGD("Focus left window: %s in display %" PRId32,
oldFocusedWindowHandle->getName().c_str(), displayId);
}
- sp<InputChannel> focusedInputChannel =
+ std::shared_ptr<InputChannel> focusedInputChannel =
getInputChannelLocked(oldFocusedWindowHandle->getToken());
if (focusedInputChannel != nullptr) {
CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
@@ -3850,7 +3852,7 @@
ALOGD("Touched window was removed: %s in display %" PRId32,
touchedWindow.windowHandle->getName().c_str(), displayId);
}
- sp<InputChannel> touchedInputChannel =
+ std::shared_ptr<InputChannel> touchedInputChannel =
getInputChannelLocked(touchedWindow.windowHandle->getToken());
if (touchedInputChannel != nullptr) {
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
@@ -3929,7 +3931,7 @@
sp<InputWindowHandle> oldFocusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, mFocusedDisplayId);
if (oldFocusedWindowHandle != nullptr) {
- sp<InputChannel> inputChannel =
+ std::shared_ptr<InputChannel> inputChannel =
getInputChannelLocked(oldFocusedWindowHandle->getToken());
if (inputChannel != nullptr) {
CancelationOptions
@@ -4376,13 +4378,13 @@
const size_t numMonitors = monitors.size();
for (size_t i = 0; i < numMonitors; i++) {
const Monitor& monitor = monitors[i];
- const sp<InputChannel>& channel = monitor.inputChannel;
+ const std::shared_ptr<InputChannel>& channel = monitor.inputChannel;
dump += StringPrintf(INDENT2 "%zu: '%s', ", i, channel->getName().c_str());
dump += "\n";
}
}
-status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel) {
+status_t InputDispatcher::registerInputChannel(const std::shared_ptr<InputChannel>& inputChannel) {
#if DEBUG_REGISTRATION
ALOGD("channel '%s' ~ registerInputChannel", inputChannel->getName().c_str());
#endif
@@ -4410,7 +4412,7 @@
return OK;
}
-status_t InputDispatcher::registerInputMonitor(const sp<InputChannel>& inputChannel,
+status_t InputDispatcher::registerInputMonitor(const std::shared_ptr<InputChannel>& inputChannel,
int32_t displayId, bool isGestureMonitor) {
{ // acquire lock
std::scoped_lock _l(mLock);
@@ -4442,9 +4444,9 @@
return OK;
}
-status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel) {
+status_t InputDispatcher::unregisterInputChannel(const InputChannel& inputChannel) {
#if DEBUG_REGISTRATION
- ALOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().c_str());
+ ALOGD("channel '%s' ~ unregisterInputChannel", inputChannel.getName().c_str());
#endif
{ // acquire lock
@@ -4462,23 +4464,23 @@
return OK;
}
-status_t InputDispatcher::unregisterInputChannelLocked(const sp<InputChannel>& inputChannel,
+status_t InputDispatcher::unregisterInputChannelLocked(const InputChannel& inputChannel,
bool notify) {
- sp<Connection> connection = getConnectionLocked(inputChannel->getConnectionToken());
+ sp<Connection> connection = getConnectionLocked(inputChannel.getConnectionToken());
if (connection == nullptr) {
ALOGW("Attempted to unregister already unregistered input channel '%s'",
- inputChannel->getName().c_str());
+ inputChannel.getName().c_str());
return BAD_VALUE;
}
removeConnectionLocked(connection);
- mInputChannelsByToken.erase(inputChannel->getConnectionToken());
+ mInputChannelsByToken.erase(inputChannel.getConnectionToken());
if (connection->monitor) {
removeMonitorChannelLocked(inputChannel);
}
- mLooper->removeFd(inputChannel->getFd());
+ mLooper->removeFd(inputChannel.getFd());
nsecs_t currentTime = now();
abortBrokenDispatchCycleLocked(currentTime, connection, notify);
@@ -4487,19 +4489,19 @@
return OK;
}
-void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) {
+void InputDispatcher::removeMonitorChannelLocked(const InputChannel& inputChannel) {
removeMonitorChannelLocked(inputChannel, mGlobalMonitorsByDisplay);
removeMonitorChannelLocked(inputChannel, mGestureMonitorsByDisplay);
}
void InputDispatcher::removeMonitorChannelLocked(
- const sp<InputChannel>& inputChannel,
+ const InputChannel& inputChannel,
std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) {
for (auto it = monitorsByDisplay.begin(); it != monitorsByDisplay.end();) {
std::vector<Monitor>& monitors = it->second;
const size_t numMonitors = monitors.size();
for (size_t i = 0; i < numMonitors; i++) {
- if (monitors[i].inputChannel == inputChannel) {
+ if (*monitors[i].inputChannel == inputChannel) {
monitors.erase(monitors.begin() + i);
break;
}
@@ -4550,7 +4552,8 @@
options.deviceId = deviceId;
options.displayId = displayId;
for (const TouchedWindow& window : state.windows) {
- sp<InputChannel> channel = getInputChannelLocked(window.windowHandle->getToken());
+ std::shared_ptr<InputChannel> channel =
+ getInputChannelLocked(window.windowHandle->getToken());
if (channel != nullptr) {
synthesizeCancelationEventsForInputChannelLocked(channel, options);
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 824bbf5..ba7ace0 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -124,10 +124,11 @@
virtual bool transferTouchFocus(const sp<IBinder>& fromToken,
const sp<IBinder>& toToken) override;
- virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel) override;
- virtual status_t registerInputMonitor(const sp<InputChannel>& inputChannel, int32_t displayId,
- bool isGestureMonitor) override;
- virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) override;
+ virtual status_t registerInputChannel(
+ const std::shared_ptr<InputChannel>& inputChannel) override;
+ virtual status_t registerInputMonitor(const std::shared_ptr<InputChannel>& inputChannel,
+ int32_t displayId, bool isGestureMonitor) override;
+ virtual status_t unregisterInputChannel(const InputChannel& inputChannel) override;
virtual status_t pilferPointers(const sp<IBinder>& token) override;
private:
@@ -210,8 +211,8 @@
return std::hash<IBinder*>{}(b.get());
}
};
- std::unordered_map<sp<IBinder>, sp<InputChannel>, IBinderHash> mInputChannelsByToken
- GUARDED_BY(mLock);
+ std::unordered_map<sp<IBinder>, std::shared_ptr<InputChannel>, IBinderHash>
+ mInputChannelsByToken GUARDED_BY(mLock);
// Finds the display ID of the gesture monitor identified by the provided token.
std::optional<int32_t> findGestureMonitorDisplayByTokenLocked(const sp<IBinder>& token)
@@ -301,7 +302,8 @@
REQUIRES(mLock);
sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken) const
REQUIRES(mLock);
- sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const REQUIRES(mLock);
+ std::shared_ptr<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const
+ REQUIRES(mLock);
bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock);
/*
@@ -459,8 +461,8 @@
void synthesizeCancelationEventsForMonitorsLocked(
const CancelationOptions& options,
std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) REQUIRES(mLock);
- void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel,
- const CancelationOptions& options)
+ void synthesizeCancelationEventsForInputChannelLocked(
+ const std::shared_ptr<InputChannel>& channel, const CancelationOptions& options)
REQUIRES(mLock);
void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection,
const CancelationOptions& options)
@@ -481,11 +483,11 @@
void logDispatchStateLocked() REQUIRES(mLock);
// Registration.
- void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock);
+ void removeMonitorChannelLocked(const InputChannel& inputChannel) REQUIRES(mLock);
void removeMonitorChannelLocked(
- const sp<InputChannel>& inputChannel,
+ const InputChannel& inputChannel,
std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) REQUIRES(mLock);
- status_t unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, bool notify)
+ status_t unregisterInputChannelLocked(const InputChannel& inputChannel, bool notify)
REQUIRES(mLock);
// Interesting events that we might like to log or tell the framework about.
diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h
index 499a75f..eeb6ee8 100644
--- a/services/inputflinger/dispatcher/InputTarget.h
+++ b/services/inputflinger/dispatcher/InputTarget.h
@@ -106,7 +106,7 @@
};
// The input channel to be targeted.
- sp<InputChannel> inputChannel;
+ std::shared_ptr<InputChannel> inputChannel;
// Flags for the input target.
int32_t flags = 0;
diff --git a/services/inputflinger/dispatcher/Monitor.cpp b/services/inputflinger/dispatcher/Monitor.cpp
index 289b084..b347674 100644
--- a/services/inputflinger/dispatcher/Monitor.cpp
+++ b/services/inputflinger/dispatcher/Monitor.cpp
@@ -19,7 +19,7 @@
namespace android::inputdispatcher {
// --- Monitor ---
-Monitor::Monitor(const sp<InputChannel>& inputChannel) : inputChannel(inputChannel) {}
+Monitor::Monitor(const std::shared_ptr<InputChannel>& inputChannel) : inputChannel(inputChannel) {}
// --- TouchedMonitor ---
TouchedMonitor::TouchedMonitor(const Monitor& monitor, float xOffset, float yOffset)
diff --git a/services/inputflinger/dispatcher/Monitor.h b/services/inputflinger/dispatcher/Monitor.h
index b67c9eb..fc0b020 100644
--- a/services/inputflinger/dispatcher/Monitor.h
+++ b/services/inputflinger/dispatcher/Monitor.h
@@ -22,9 +22,9 @@
namespace android::inputdispatcher {
struct Monitor {
- sp<InputChannel> inputChannel; // never null
+ std::shared_ptr<InputChannel> inputChannel; // never null
- explicit Monitor(const sp<InputChannel>& inputChannel);
+ explicit Monitor(const std::shared_ptr<InputChannel>& inputChannel);
};
// For tracking the offsets we need to apply when adding gesture monitor targets.
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index f25131c..272b0a6 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -152,7 +152,7 @@
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel) = 0;
+ virtual status_t registerInputChannel(const std::shared_ptr<InputChannel>& inputChannel) = 0;
/* Registers input channels to be used to monitor input events.
*
@@ -162,14 +162,14 @@
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual status_t registerInputMonitor(const sp<InputChannel>& inputChannel, int32_t displayId,
- bool gestureMonitor) = 0;
+ virtual status_t registerInputMonitor(const std::shared_ptr<InputChannel>& inputChannel,
+ int32_t displayId, bool gestureMonitor) = 0;
/* Unregister input channels that will no longer receive input events.
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
+ virtual status_t unregisterInputChannel(const InputChannel& inputChannel) = 0;
/* Allows an input monitor steal the current pointer stream away from normal input windows.
*
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index 9364a2a..cd655e0 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -48,8 +48,8 @@
const sp<ISetInputWindowsListener>&) {
return binder::Status::ok();
}
- binder::Status registerInputChannel(const InputChannelInfo&) { return binder::Status::ok(); }
- binder::Status unregisterInputChannel(const InputChannelInfo&) { return binder::Status::ok(); }
+ binder::Status registerInputChannel(const InputChannel&) { return binder::Status::ok(); }
+ binder::Status unregisterInputChannel(const InputChannel&) { return binder::Status::ok(); }
private:
virtual ~InputFlinger();
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 0fa8787..5a832e7 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -17,23 +17,24 @@
#ifndef _UI_INPUT_READER_BASE_H
#define _UI_INPUT_READER_BASE_H
-#include "PointerControllerInterface.h"
-
#include <input/DisplayViewport.h>
#include <input/Input.h>
#include <input/InputDevice.h>
#include <input/VelocityControl.h>
#include <input/VelocityTracker.h>
+#include <stddef.h>
+#include <unistd.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
-#include <stddef.h>
-#include <unistd.h>
#include <optional>
#include <set>
#include <unordered_map>
#include <vector>
+#include "PointerControllerInterface.h"
+#include "VibrationElement.h"
+
// Maximum supported size of a vibration pattern.
// Must be at least 2.
#define MAX_VIBRATE_PATTERN_SIZE 100
@@ -41,6 +42,7 @@
// Maximum allowable delay value in a vibration pattern before
// which the delay will be truncated.
#define MAX_VIBRATE_PATTERN_DELAY_NSECS (1000000 * 1000000000LL)
+#define MAX_VIBRATE_PATTERN_DELAY_MSECS (1000000 * 1000LL)
namespace android {
@@ -104,8 +106,8 @@
virtual void requestRefreshConfiguration(uint32_t changes) = 0;
/* Controls the vibrator of a particular input device. */
- virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize,
- ssize_t repeat, int32_t token) = 0;
+ virtual void vibrate(int32_t deviceId, const std::vector<VibrationElement>& pattern,
+ ssize_t repeat, int32_t token) = 0;
virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0;
/* Return true if the device can send input events to the specified display. */
diff --git a/services/inputflinger/include/VibrationElement.h b/services/inputflinger/include/VibrationElement.h
new file mode 100644
index 0000000..8a134ee
--- /dev/null
+++ b/services/inputflinger/include/VibrationElement.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef _VIBRATION_ELEMENT_H
+#define _VIBRATION_ELEMENT_H
+
+#include <chrono>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+namespace android {
+
+/*
+ * Describes a rumble effect
+ */
+struct VibrationElement {
+ std::chrono::milliseconds duration;
+ std::vector<int> channels;
+
+ void dump(std::string& dump) const;
+ uint16_t getChannel(int id) const;
+ bool isOn() const;
+};
+
+} // namespace android
+
+#endif // _VIBRATION_ELEMENT_H
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 5e590d0..cef2b4c 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -43,22 +43,11 @@
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/Timers.h>
-#include <utils/threads.h>
#include <filesystem>
#include "EventHub.h"
-/* this macro is used to tell if "bit" is set in "array"
- * it selects a byte from the array, and does a boolean AND
- * operation with a byte that only has the relevant bit set.
- * eg. to check for the 12th bit, we do (array[1] & 1<<4)
- */
-#define test_bit(bit, array) ((array)[(bit) / 8] & (1 << ((bit) % 8)))
-
-/* this macro computes the number of bytes needed to represent a bit array of the specified size */
-#define sizeof_bit_array(bits) (((bits) + 7) / 8)
-
#define INDENT " "
#define INDENT2 " "
#define INDENT3 " "
@@ -193,15 +182,7 @@
ffEffectId(-1),
controllerNumber(0),
enabled(true),
- isVirtual(fd < 0) {
- memset(keyBitmask, 0, sizeof(keyBitmask));
- memset(absBitmask, 0, sizeof(absBitmask));
- memset(relBitmask, 0, sizeof(relBitmask));
- memset(swBitmask, 0, sizeof(swBitmask));
- memset(ledBitmask, 0, sizeof(ledBitmask));
- memset(ffBitmask, 0, sizeof(ffBitmask));
- memset(propBitmask, 0, sizeof(propBitmask));
-}
+ isVirtual(fd < 0) {}
EventHub::Device::~Device() {
close();
@@ -391,7 +372,7 @@
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && device->hasValidFd() && test_bit(axis, device->absBitmask)) {
+ if (device != nullptr && device->hasValidFd() && device->absBitmask.test(axis)) {
struct input_absinfo info;
if (ioctl(device->fd, EVIOCGABS(axis), &info)) {
ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", axis,
@@ -418,9 +399,7 @@
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device) {
- return test_bit(axis, device->relBitmask);
- }
+ return device != nullptr ? device->relBitmask.test(axis) : false;
}
return false;
}
@@ -430,9 +409,7 @@
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device) {
- return test_bit(property, device->propBitmask);
- }
+ return device != nullptr ? device->propBitmask.test(property) : false;
}
return false;
}
@@ -442,11 +419,9 @@
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && device->hasValidFd() && test_bit(scanCode, device->keyBitmask)) {
- uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)];
- memset(keyState, 0, sizeof(keyState));
- if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) {
- return test_bit(scanCode, keyState) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
+ if (device != nullptr && device->hasValidFd() && device->keyBitmask.test(scanCode)) {
+ if (device->readDeviceBitMask(EVIOCGKEY(0), device->keyState) >= 0) {
+ return device->keyState.test(scanCode) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
}
}
}
@@ -457,16 +432,14 @@
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && device->hasValidFd() && device->keyMap.haveKeyLayout()) {
+ if (device != nullptr && device->hasValidFd() && device->keyMap.haveKeyLayout()) {
std::vector<int32_t> scanCodes;
device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes);
if (scanCodes.size() != 0) {
- uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)];
- memset(keyState, 0, sizeof(keyState));
- if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) {
+ if (device->readDeviceBitMask(EVIOCGKEY(0), device->keyState) >= 0) {
for (size_t i = 0; i < scanCodes.size(); i++) {
int32_t sc = scanCodes[i];
- if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, keyState)) {
+ if (sc >= 0 && sc <= KEY_MAX && device->keyState.test(sc)) {
return AKEY_STATE_DOWN;
}
}
@@ -482,11 +455,9 @@
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && device->hasValidFd() && test_bit(sw, device->swBitmask)) {
- uint8_t swState[sizeof_bit_array(SW_MAX + 1)];
- memset(swState, 0, sizeof(swState));
- if (ioctl(device->fd, EVIOCGSW(sizeof(swState)), swState) >= 0) {
- return test_bit(sw, swState) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
+ if (device != nullptr && device->hasValidFd() && device->swBitmask.test(sw)) {
+ if (device->readDeviceBitMask(EVIOCGSW(0), device->swState) >= 0) {
+ return device->swState.test(sw) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
}
}
}
@@ -500,7 +471,7 @@
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && device->hasValidFd() && test_bit(axis, device->absBitmask)) {
+ if (device != nullptr && device->hasValidFd() && device->absBitmask.test(axis)) {
struct input_absinfo info;
if (ioctl(device->fd, EVIOCGABS(axis), &info)) {
ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", axis,
@@ -520,7 +491,7 @@
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && device->keyMap.haveKeyLayout()) {
+ if (device != nullptr && device->keyMap.haveKeyLayout()) {
std::vector<int32_t> scanCodes;
for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
scanCodes.clear();
@@ -531,7 +502,7 @@
// check the possible scan codes identified by the layout map against the
// map of codes actually emitted by the driver
for (size_t sc = 0; sc < scanCodes.size(); sc++) {
- if (test_bit(scanCodes[sc], device->keyBitmask)) {
+ if (device->keyBitmask.test(scanCodes[sc])) {
outFlags[codeIndex] = 1;
break;
}
@@ -549,7 +520,7 @@
Device* device = getDeviceLocked(deviceId);
status_t status = NAME_NOT_FOUND;
- if (device) {
+ if (device != nullptr) {
// Check the key character map first.
sp<KeyCharacterMap> kcm = device->getKeyCharacterMap();
if (kcm != nullptr) {
@@ -588,7 +559,7 @@
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && device->keyMap.haveKeyLayout()) {
+ if (device != nullptr && device->keyMap.haveKeyLayout()) {
status_t err = device->keyMap.keyLayoutMap->mapAxis(scanCode, outAxisInfo);
if (err == NO_ERROR) {
return NO_ERROR;
@@ -607,10 +578,8 @@
bool EventHub::hasScanCode(int32_t deviceId, int32_t scanCode) const {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && scanCode >= 0 && scanCode <= KEY_MAX) {
- if (test_bit(scanCode, device->keyBitmask)) {
- return true;
- }
+ if (device != nullptr && scanCode >= 0 && scanCode <= KEY_MAX) {
+ return device->keyBitmask.test(scanCode);
}
return false;
}
@@ -619,10 +588,8 @@
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
int32_t sc;
- if (device && mapLed(device, led, &sc) == NO_ERROR) {
- if (test_bit(sc, device->ledBitmask)) {
- return true;
- }
+ if (device != nullptr && mapLed(device, led, &sc) == NO_ERROR) {
+ return device->ledBitmask.test(sc);
}
return false;
}
@@ -635,7 +602,7 @@
void EventHub::setLedStateLocked(Device* device, int32_t led, bool on) {
int32_t sc;
- if (device && device->hasValidFd() && mapLed(device, led, &sc) != NAME_NOT_FOUND) {
+ if (device != nullptr && device->hasValidFd() && mapLed(device, led, &sc) != NAME_NOT_FOUND) {
struct input_event ev;
ev.time.tv_sec = 0;
ev.time.tv_usec = 0;
@@ -656,7 +623,7 @@
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && device->virtualKeyMap) {
+ if (device != nullptr && device->virtualKeyMap) {
const std::vector<VirtualKeyDefinition> virtualKeys =
device->virtualKeyMap->getVirtualKeys();
outVirtualKeys.insert(outVirtualKeys.end(), virtualKeys.begin(), virtualKeys.end());
@@ -666,7 +633,7 @@
sp<KeyCharacterMap> EventHub::getKeyCharacterMap(int32_t deviceId) const {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device) {
+ if (device != nullptr) {
return device->getKeyCharacterMap();
}
return nullptr;
@@ -675,7 +642,7 @@
bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device) {
+ if (device != nullptr) {
if (map != device->overlayKeyMap) {
device->overlayKeyMap = map;
device->combinedKeyMap = KeyCharacterMap::combine(device->keyMap.keyCharacterMap, map);
@@ -735,17 +702,18 @@
identifier.descriptor.c_str());
}
-void EventHub::vibrate(int32_t deviceId, nsecs_t duration) {
+void EventHub::vibrate(int32_t deviceId, const VibrationElement& element) {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && device->hasValidFd()) {
+ if (device != nullptr && device->hasValidFd()) {
ff_effect effect;
memset(&effect, 0, sizeof(effect));
effect.type = FF_RUMBLE;
effect.id = device->ffEffectId;
- effect.u.rumble.strong_magnitude = 0xc000;
- effect.u.rumble.weak_magnitude = 0xc000;
- effect.replay.length = (duration + 999999LL) / 1000000LL;
+ // evdev FF_RUMBLE effect only supports two channels of vibration.
+ effect.u.rumble.strong_magnitude = element.getChannel(0);
+ effect.u.rumble.weak_magnitude = element.getChannel(1);
+ effect.replay.length = element.duration.count();
effect.replay.delay = 0;
if (ioctl(device->fd, EVIOCSFF, &effect)) {
ALOGW("Could not upload force feedback effect to device %s due to error %d.",
@@ -772,7 +740,7 @@
void EventHub::cancelVibrate(int32_t deviceId) {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && device->hasValidFd()) {
+ if (device != nullptr && device->hasValidFd()) {
if (device->ffEffectPlaying) {
device->ffEffectPlaying = false;
@@ -1089,7 +1057,7 @@
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (!device || !device->videoDevice) {
+ if (device == nullptr || !device->videoDevice) {
return {};
}
return device->videoDevice->consumeFrames();
@@ -1126,17 +1094,6 @@
// ----------------------------------------------------------------------------
-static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex) {
- const uint8_t* end = array + endIndex;
- array += startIndex;
- while (array != end) {
- if (*(array++) != 0) {
- return true;
- }
- }
- return false;
-}
-
static const int32_t GAMEPAD_KEYCODES[] = {
AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C, //
AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z, //
@@ -1306,31 +1263,27 @@
loadConfigurationLocked(device);
// Figure out the kinds of events the device reports.
- ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);
- ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask);
- ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask);
- ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask);
- ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask);
- ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask);
- ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);
+ device->readDeviceBitMask(EVIOCGBIT(EV_KEY, 0), device->keyBitmask);
+ device->readDeviceBitMask(EVIOCGBIT(EV_ABS, 0), device->absBitmask);
+ device->readDeviceBitMask(EVIOCGBIT(EV_REL, 0), device->relBitmask);
+ device->readDeviceBitMask(EVIOCGBIT(EV_SW, 0), device->swBitmask);
+ device->readDeviceBitMask(EVIOCGBIT(EV_LED, 0), device->ledBitmask);
+ device->readDeviceBitMask(EVIOCGBIT(EV_FF, 0), device->ffBitmask);
+ device->readDeviceBitMask(EVIOCGPROP(0), device->propBitmask);
// See if this is a keyboard. Ignore everything in the button range except for
// joystick and gamepad buttons which are handled like keyboards for the most part.
bool haveKeyboardKeys =
- containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC)) ||
- containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_WHEEL),
- sizeof_bit_array(KEY_MAX + 1));
- bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC),
- sizeof_bit_array(BTN_MOUSE)) ||
- containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK),
- sizeof_bit_array(BTN_DIGI));
+ device->keyBitmask.any(0, BTN_MISC) || device->keyBitmask.any(BTN_WHEEL, KEY_MAX + 1);
+ bool haveGamepadButtons = device->keyBitmask.any(BTN_MISC, BTN_MOUSE) ||
+ device->keyBitmask.any(BTN_JOYSTICK, BTN_DIGI);
if (haveKeyboardKeys || haveGamepadButtons) {
device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
}
// See if this is a cursor device such as a trackball or mouse.
- if (test_bit(BTN_MOUSE, device->keyBitmask) && test_bit(REL_X, device->relBitmask) &&
- test_bit(REL_Y, device->relBitmask)) {
+ if (device->keyBitmask.test(BTN_MOUSE) && device->relBitmask.test(REL_X) &&
+ device->relBitmask.test(REL_Y)) {
device->classes |= INPUT_DEVICE_CLASS_CURSOR;
}
@@ -1345,22 +1298,20 @@
// See if this is a touch pad.
// Is this a new modern multi-touch driver?
- if (test_bit(ABS_MT_POSITION_X, device->absBitmask) &&
- test_bit(ABS_MT_POSITION_Y, device->absBitmask)) {
+ if (device->absBitmask.test(ABS_MT_POSITION_X) && device->absBitmask.test(ABS_MT_POSITION_Y)) {
// Some joysticks such as the PS3 controller report axes that conflict
// with the ABS_MT range. Try to confirm that the device really is
// a touch screen.
- if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) {
+ if (device->keyBitmask.test(BTN_TOUCH) || !haveGamepadButtons) {
device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;
}
// Is this an old style single-touch driver?
- } else if (test_bit(BTN_TOUCH, device->keyBitmask) && test_bit(ABS_X, device->absBitmask) &&
- test_bit(ABS_Y, device->absBitmask)) {
+ } else if (device->keyBitmask.test(BTN_TOUCH) && device->absBitmask.test(ABS_X) &&
+ device->absBitmask.test(ABS_Y)) {
device->classes |= INPUT_DEVICE_CLASS_TOUCH;
// Is this a BT stylus?
- } else if ((test_bit(ABS_PRESSURE, device->absBitmask) ||
- test_bit(BTN_TOUCH, device->keyBitmask)) &&
- !test_bit(ABS_X, device->absBitmask) && !test_bit(ABS_Y, device->absBitmask)) {
+ } else if ((device->absBitmask.test(ABS_PRESSURE) || device->keyBitmask.test(BTN_TOUCH)) &&
+ !device->absBitmask.test(ABS_X) && !device->absBitmask.test(ABS_Y)) {
device->classes |= INPUT_DEVICE_CLASS_EXTERNAL_STYLUS;
// Keyboard will try to claim some of the buttons but we really want to reserve those so we
// can fuse it with the touch screen data, so just take them back. Note this means an
@@ -1374,7 +1325,7 @@
if (haveGamepadButtons) {
uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK;
for (int i = 0; i <= ABS_MAX; i++) {
- if (test_bit(i, device->absBitmask) &&
+ if (device->absBitmask.test(i) &&
(getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) {
device->classes = assumedClasses;
break;
@@ -1384,14 +1335,14 @@
// Check whether this device has switches.
for (int i = 0; i <= SW_MAX; i++) {
- if (test_bit(i, device->swBitmask)) {
+ if (device->swBitmask.test(i)) {
device->classes |= INPUT_DEVICE_CLASS_SWITCH;
break;
}
}
// Check whether this device supports the vibrator.
- if (test_bit(FF_RUMBLE, device->ffBitmask)) {
+ if (device->ffBitmask.test(FF_RUMBLE)) {
device->classes |= INPUT_DEVICE_CLASS_VIBRATOR;
}
@@ -1703,7 +1654,7 @@
const size_t N = scanCodes.size();
for (size_t i = 0; i < N && i <= KEY_MAX; i++) {
int32_t sc = scanCodes[i];
- if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) {
+ if (sc >= 0 && sc <= KEY_MAX && device->keyBitmask.test(sc)) {
return true;
}
}
@@ -1718,7 +1669,7 @@
int32_t scanCode;
if (device->keyMap.keyLayoutMap->findScanCodeForLed(led, &scanCode) != NAME_NOT_FOUND) {
- if (scanCode >= 0 && scanCode <= LED_MAX && test_bit(scanCode, device->ledBitmask)) {
+ if (scanCode >= 0 && scanCode <= LED_MAX && device->ledBitmask.test(scanCode)) {
*outScanCode = scanCode;
return NO_ERROR;
}
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 4b19e5e..b4eaf7f 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -424,10 +424,10 @@
return result;
}
-void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
+void InputDevice::vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat,
int32_t token) {
- for_each_mapper([pattern, patternSize, repeat, token](InputMapper& mapper) {
- mapper.vibrate(pattern, patternSize, repeat, token);
+ for_each_mapper([pattern, repeat, token](InputMapper& mapper) {
+ mapper.vibrate(pattern, repeat, token);
});
}
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 06e3743..16fe865 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -559,12 +559,12 @@
}
}
-void InputReader::vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize,
+void InputReader::vibrate(int32_t deviceId, const std::vector<VibrationElement>& pattern,
ssize_t repeat, int32_t token) {
AutoMutex _l(mLock);
InputDevice* device = findInputDevice(deviceId);
if (device) {
- device->vibrate(pattern, patternSize, repeat, token);
+ device->vibrate(pattern, repeat, token);
}
}
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index ee62c9a..c5dfcfd 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -17,6 +17,8 @@
#ifndef _RUNTIME_EVENT_HUB_H
#define _RUNTIME_EVENT_HUB_H
+#include <bitset>
+#include <climits>
#include <vector>
#include <input/Input.h>
@@ -25,6 +27,8 @@
#include <input/KeyLayoutMap.h>
#include <input/Keyboard.h>
#include <input/VirtualKeyMap.h>
+#include <linux/input.h>
+#include <sys/epoll.h>
#include <utils/BitSet.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
@@ -33,15 +37,8 @@
#include <utils/Mutex.h>
#include <utils/PropertyMap.h>
-#include <linux/input.h>
-#include <sys/epoll.h>
-
#include "TouchVideoDevice.h"
-
-/* Convenience constants. */
-
-#define BTN_FIRST 0x100 // first button code
-#define BTN_LAST 0x15f // last button code
+#include "VibrationElement.h"
namespace android {
@@ -231,7 +228,7 @@
virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) = 0;
/* Control the vibrator. */
- virtual void vibrate(int32_t deviceId, nsecs_t duration) = 0;
+ virtual void vibrate(int32_t deviceId, const VibrationElement& effect) = 0;
virtual void cancelVibrate(int32_t deviceId) = 0;
/* Requests the EventHub to reopen all input devices on the next call to getEvents(). */
@@ -256,6 +253,76 @@
virtual status_t disableDevice(int32_t deviceId) = 0;
};
+template <std::size_t BITS>
+class BitArray {
+ /* Array element type and vector of element type. */
+ using Element = std::uint32_t;
+ /* Number of bits in each BitArray element. */
+ static constexpr size_t WIDTH = sizeof(Element) * CHAR_BIT;
+ /* Number of elements to represent a bit array of the specified size of bits. */
+ static constexpr size_t COUNT = (BITS + WIDTH - 1) / WIDTH;
+
+public:
+ /* BUFFER type declaration for BitArray */
+ using Buffer = std::array<Element, COUNT>;
+ /* To tell if a bit is set in array, it selects an element from the array, and test
+ * if the relevant bit set.
+ * Note the parameter "bit" is an index to the bit, 0 <= bit < BITS.
+ */
+ inline bool test(size_t bit) const {
+ return (bit < BITS) ? mData[bit / WIDTH].test(bit % WIDTH) : false;
+ }
+ /* Returns total number of bytes needed for the array */
+ inline size_t bytes() { return (BITS + CHAR_BIT - 1) / CHAR_BIT; }
+ /* Returns true if array contains any non-zero bit from the range defined by start and end
+ * bit index [startIndex, endIndex).
+ */
+ bool any(size_t startIndex, size_t endIndex) {
+ if (startIndex >= endIndex || startIndex > BITS || endIndex > BITS + 1) {
+ ALOGE("Invalid start/end index. start = %zu, end = %zu, total bits = %zu", startIndex,
+ endIndex, BITS);
+ return false;
+ }
+ size_t se = startIndex / WIDTH; // Start of element
+ size_t ee = endIndex / WIDTH; // End of element
+ size_t si = startIndex % WIDTH; // Start index in start element
+ size_t ei = endIndex % WIDTH; // End index in end element
+ // Need to check first unaligned bitset for any non zero bit
+ if (si > 0) {
+ size_t nBits = se == ee ? ei - si : WIDTH - si;
+ // Generate the mask of interested bit range
+ Element mask = ((1 << nBits) - 1) << si;
+ if (mData[se++].to_ulong() & mask) {
+ return true;
+ }
+ }
+ // Check whole bitset for any bit set
+ for (; se < ee; se++) {
+ if (mData[se].any()) {
+ return true;
+ }
+ }
+ // Need to check last unaligned bitset for any non zero bit
+ if (ei > 0 && se <= ee) {
+ // Generate the mask of interested bit range
+ Element mask = (1 << ei) - 1;
+ if (mData[se].to_ulong() & mask) {
+ return true;
+ }
+ }
+ return false;
+ }
+ /* Load bit array values from buffer */
+ void loadFromBuffer(const Buffer& buffer) {
+ for (size_t i = 0; i < COUNT; i++) {
+ mData[i] = std::bitset<WIDTH>(buffer[i]);
+ }
+ }
+
+private:
+ std::array<std::bitset<WIDTH>, COUNT> mData;
+};
+
class EventHub : public EventHubInterface {
public:
EventHub();
@@ -307,7 +374,7 @@
virtual bool setKeyboardLayoutOverlay(int32_t deviceId,
const sp<KeyCharacterMap>& map) override;
- virtual void vibrate(int32_t deviceId, nsecs_t duration) override;
+ virtual void vibrate(int32_t deviceId, const VibrationElement& effect) override;
virtual void cancelVibrate(int32_t deviceId) override;
virtual void requestReopenDevices() override;
@@ -332,13 +399,15 @@
uint32_t classes;
- uint8_t keyBitmask[(KEY_MAX + 1) / 8];
- uint8_t absBitmask[(ABS_MAX + 1) / 8];
- uint8_t relBitmask[(REL_MAX + 1) / 8];
- uint8_t swBitmask[(SW_MAX + 1) / 8];
- uint8_t ledBitmask[(LED_MAX + 1) / 8];
- uint8_t ffBitmask[(FF_MAX + 1) / 8];
- uint8_t propBitmask[(INPUT_PROP_MAX + 1) / 8];
+ BitArray<KEY_MAX> keyBitmask;
+ BitArray<KEY_MAX> keyState;
+ BitArray<ABS_MAX> absBitmask;
+ BitArray<REL_MAX> relBitmask;
+ BitArray<SW_MAX> swBitmask;
+ BitArray<SW_MAX> swState;
+ BitArray<LED_MAX> ledBitmask;
+ BitArray<FF_MAX> ffBitmask;
+ BitArray<INPUT_PROP_MAX> propBitmask;
std::string configurationFile;
PropertyMap* configuration;
@@ -371,6 +440,21 @@
}
return keyMap.keyCharacterMap;
}
+
+ template <std::size_t N>
+ status_t readDeviceBitMask(unsigned long ioctlCode, BitArray<N>& bitArray) {
+ if (!hasValidFd()) {
+ return BAD_VALUE;
+ }
+ if ((_IOC_SIZE(ioctlCode) == 0)) {
+ ioctlCode |= _IOC(0, 0, 0, bitArray.bytes());
+ }
+
+ typename BitArray<N>::Buffer buffer;
+ status_t ret = ioctl(fd, ioctlCode, buffer.data());
+ bitArray.loadFromBuffer(buffer);
+ return ret;
+ }
};
status_t openDeviceLocked(const std::string& devicePath);
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 71313fc..6cb86bd 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -81,7 +81,7 @@
int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes,
uint8_t* outFlags);
- void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token);
+ void vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat, int32_t token);
void cancelVibrate(int32_t token);
void cancelTouch(nsecs_t when);
@@ -262,7 +262,9 @@
inline bool setKeyboardLayoutOverlay(const sp<KeyCharacterMap>& map) {
return mEventHub->setKeyboardLayoutOverlay(mId, map);
}
- inline void vibrate(nsecs_t duration) { return mEventHub->vibrate(mId, duration); }
+ inline void vibrate(const VibrationElement& element) {
+ return mEventHub->vibrate(mId, element);
+ }
inline void cancelVibrate() { return mEventHub->cancelVibrate(mId); }
inline bool hasAbsoluteAxis(int32_t code) const {
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 108b9c2..9cb2052 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -78,7 +78,7 @@
virtual void requestRefreshConfiguration(uint32_t changes) override;
- virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize,
+ virtual void vibrate(int32_t deviceId, const std::vector<VibrationElement>& pattern,
ssize_t repeat, int32_t token) override;
virtual void cancelVibrate(int32_t deviceId, int32_t token) override;
diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp
index a8fe39a..1db829f 100644
--- a/services/inputflinger/reader/mapper/InputMapper.cpp
+++ b/services/inputflinger/reader/mapper/InputMapper.cpp
@@ -56,7 +56,7 @@
return false;
}
-void InputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
+void InputMapper::vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat,
int32_t token) {}
void InputMapper::cancelVibrate(int32_t token) {}
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index 949c7ea..d9fc5cc 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -22,6 +22,7 @@
#include "InputListener.h"
#include "InputReaderContext.h"
#include "StylusState.h"
+#include "VibrationElement.h"
namespace android {
@@ -62,7 +63,8 @@
virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags);
- virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token);
+ virtual void vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat,
+ int32_t token);
virtual void cancelVibrate(int32_t token);
virtual void cancelTouch(nsecs_t when);
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index 43bd9f1..0440f49 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -236,6 +236,20 @@
mMultiTouchMotionAccumulator.process(rawEvent);
}
+std::optional<int32_t> MultiTouchInputMapper::getActiveBitId(
+ const MultiTouchMotionAccumulator::Slot& inSlot) {
+ if (mHavePointerIds) {
+ int32_t trackingId = inSlot.getTrackingId();
+ for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty();) {
+ int32_t n = idBits.clearFirstMarkedBit();
+ if (mPointerTrackingIdMap[n] == trackingId) {
+ return std::make_optional(n);
+ }
+ }
+ }
+ return std::nullopt;
+}
+
void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();
size_t outCount = 0;
@@ -250,10 +264,9 @@
}
if (inSlot->getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) {
- if (!mCurrentMotionAborted) {
- ALOGI("Canceling touch gesture from device %s because the palm event was detected",
- getDeviceName().c_str());
- cancelTouch(when);
+ std::optional<int32_t> id = getActiveBitId(*inSlot);
+ if (id) {
+ outState->rawPointerData.canceledIdBits.markBit(id.value());
}
continue;
}
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
index 190282f..ea6f207 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
@@ -103,6 +103,8 @@
bool hasStylus() const override;
private:
+ // If the slot is in use, return the bit id. Return std::nullopt otherwise.
+ std::optional<int32_t> getActiveBitId(const MultiTouchMotionAccumulator::Slot& inSlot);
MultiTouchMotionAccumulator mMultiTouchMotionAccumulator;
// Specifies the pointer id bits that are in use, and their associated tracking id.
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 4274ca8..15d5288 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -104,6 +104,7 @@
pointerCount = other.pointerCount;
hoveringIdBits = other.hoveringIdBits;
touchingIdBits = other.touchingIdBits;
+ canceledIdBits = other.canceledIdBits;
for (uint32_t i = 0; i < pointerCount; i++) {
pointers[i] = other.pointers[i];
@@ -140,6 +141,7 @@
pointerCount = 0;
hoveringIdBits.clear();
touchingIdBits.clear();
+ canceledIdBits.clear();
}
void CookedPointerData::copyFrom(const CookedPointerData& other) {
@@ -1444,10 +1446,11 @@
#if DEBUG_RAW_EVENTS
ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, "
- "hovering ids 0x%08x -> 0x%08x",
+ "hovering ids 0x%08x -> 0x%08x, canceled ids 0x%08x",
last->rawPointerData.pointerCount, next->rawPointerData.pointerCount,
last->rawPointerData.touchingIdBits.value, next->rawPointerData.touchingIdBits.value,
- last->rawPointerData.hoveringIdBits.value, next->rawPointerData.hoveringIdBits.value);
+ last->rawPointerData.hoveringIdBits.value, next->rawPointerData.hoveringIdBits.value,
+ next->rawPointerData.canceledIdBits.value);
#endif
processRawTouches(false /*timeout*/);
@@ -1892,14 +1895,15 @@
// Dispatch pointer up events.
while (!upIdBits.isEmpty()) {
uint32_t upId = upIdBits.clearFirstMarkedBit();
-
- dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, 0,
- metaState, buttonState, 0,
+ bool isCanceled = mCurrentCookedState.cookedPointerData.canceledIdBits.hasBit(upId);
+ dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0,
+ isCanceled ? AMOTION_EVENT_FLAG_CANCELED : 0, metaState, buttonState, 0,
mLastCookedState.cookedPointerData.pointerProperties,
mLastCookedState.cookedPointerData.pointerCoords,
mLastCookedState.cookedPointerData.idToIndex, dispatchedIdBits, upId,
mOrientedXPrecision, mOrientedYPrecision, mDownTime);
dispatchedIdBits.clearBit(upId);
+ mCurrentCookedState.cookedPointerData.canceledIdBits.clearBit(upId);
}
// Dispatch move events if any of the remaining pointers moved from their old locations.
@@ -2025,6 +2029,8 @@
mCurrentRawState.rawPointerData.hoveringIdBits;
mCurrentCookedState.cookedPointerData.touchingIdBits =
mCurrentRawState.rawPointerData.touchingIdBits;
+ mCurrentCookedState.cookedPointerData.canceledIdBits =
+ mCurrentRawState.rawPointerData.canceledIdBits;
if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {
mCurrentCookedState.buttonState = 0;
@@ -3563,7 +3569,11 @@
if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
action = AMOTION_EVENT_ACTION_DOWN;
} else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
- action = AMOTION_EVENT_ACTION_UP;
+ if ((flags & AMOTION_EVENT_FLAG_CANCELED) != 0) {
+ action = AMOTION_EVENT_ACTION_CANCEL;
+ } else {
+ action = AMOTION_EVENT_ACTION_UP;
+ }
} else {
// Can't happen.
ALOG_ASSERT(false);
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index d437e01..94486a6 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -71,7 +71,7 @@
uint32_t pointerCount;
Pointer pointers[MAX_POINTERS];
- BitSet32 hoveringIdBits, touchingIdBits;
+ BitSet32 hoveringIdBits, touchingIdBits, canceledIdBits;
uint32_t idToIndex[MAX_POINTER_ID + 1];
RawPointerData();
@@ -90,6 +90,7 @@
inline void clearIdBits() {
hoveringIdBits.clear();
touchingIdBits.clear();
+ canceledIdBits.clear();
}
inline const Pointer& pointerForId(uint32_t id) const { return pointers[idToIndex[id]]; }
@@ -102,7 +103,7 @@
uint32_t pointerCount;
PointerProperties pointerProperties[MAX_POINTERS];
PointerCoords pointerCoords[MAX_POINTERS];
- BitSet32 hoveringIdBits, touchingIdBits;
+ BitSet32 hoveringIdBits, touchingIdBits, canceledIdBits;
uint32_t idToIndex[MAX_POINTER_ID + 1];
CookedPointerData();
diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
index 7665680..8c1e224 100644
--- a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
@@ -39,23 +39,17 @@
// TODO: Handle FF_STATUS, although it does not seem to be widely supported.
}
-void VibratorInputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
+void VibratorInputMapper::vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat,
int32_t token) {
#if DEBUG_VIBRATOR
std::string patternStr;
- for (size_t i = 0; i < patternSize; i++) {
- if (i != 0) {
- patternStr += ", ";
- }
- patternStr += StringPrintf("%" PRId64, pattern[i]);
- }
+ dumpPattern(patternStr);
ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%zd, token=%d", getDeviceId(),
patternStr.c_str(), repeat, token);
#endif
mVibrating = true;
- memcpy(mPattern, pattern, patternSize * sizeof(nsecs_t));
- mPatternSize = patternSize;
+ mPattern = pattern;
mRepeat = repeat;
mToken = token;
mIndex = -1;
@@ -85,7 +79,7 @@
void VibratorInputMapper::nextStep() {
mIndex += 1;
- if (size_t(mIndex) >= mPatternSize) {
+ if (size_t(mIndex) >= mPattern.size()) {
if (mRepeat < 0) {
// We are done.
stopVibrating();
@@ -94,13 +88,15 @@
mIndex = mRepeat;
}
- bool vibratorOn = mIndex & 1;
- nsecs_t duration = mPattern[mIndex];
- if (vibratorOn) {
+ const VibrationElement& element = mPattern[mIndex];
+ if (element.isOn()) {
#if DEBUG_VIBRATOR
- ALOGD("nextStep: sending vibrate deviceId=%d, duration=%" PRId64, getDeviceId(), duration);
+ std::string description;
+ element.dump(description);
+ ALOGD("nextStep: sending vibrate deviceId=%d, element=%s", getDeviceId(),
+ description.c_str());
#endif
- getDeviceContext().vibrate(duration);
+ getDeviceContext().vibrate(element);
} else {
#if DEBUG_VIBRATOR
ALOGD("nextStep: sending cancel vibrate deviceId=%d", getDeviceId());
@@ -108,10 +104,12 @@
getDeviceContext().cancelVibrate();
}
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- mNextStepTime = now + duration;
+ std::chrono::nanoseconds duration =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(element.duration);
+ mNextStepTime = now + duration.count();
getContext()->requestTimeoutAtTime(mNextStepTime);
#if DEBUG_VIBRATOR
- ALOGD("nextStep: scheduled timeout in %0.3fms", duration * 0.000001f);
+ ALOGD("nextStep: scheduled timeout in %lldms", element.duration.count());
#endif
}
@@ -126,6 +124,25 @@
void VibratorInputMapper::dump(std::string& dump) {
dump += INDENT2 "Vibrator Input Mapper:\n";
dump += StringPrintf(INDENT3 "Vibrating: %s\n", toString(mVibrating));
+ if (mVibrating) {
+ dump += INDENT3 "Pattern: ";
+ dumpPattern(dump);
+ dump += "\n";
+ dump += StringPrintf(INDENT3 "Repeat Index: %zd\n", mRepeat);
+ }
+}
+
+void VibratorInputMapper::dumpPattern(std::string& dump) const {
+ dump += "[";
+
+ if (mPattern.size() > 0) {
+ mPattern[0].dump(dump);
+ std::for_each(mPattern.begin() + 1, mPattern.end(), [&dump](const auto& element) {
+ dump += ", ";
+ element.dump(dump);
+ });
+ }
+ dump += "]";
}
} // namespace android
diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.h b/services/inputflinger/reader/mapper/VibratorInputMapper.h
index f69fdde..bfa5ec1 100644
--- a/services/inputflinger/reader/mapper/VibratorInputMapper.h
+++ b/services/inputflinger/reader/mapper/VibratorInputMapper.h
@@ -30,7 +30,7 @@
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
virtual void process(const RawEvent* rawEvent) override;
- virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
+ virtual void vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat,
int32_t token) override;
virtual void cancelVibrate(int32_t token) override;
virtual void timeoutExpired(nsecs_t when) override;
@@ -38,13 +38,13 @@
private:
bool mVibrating;
- nsecs_t mPattern[MAX_VIBRATE_PATTERN_SIZE];
- size_t mPatternSize;
+ std::vector<VibrationElement> mPattern;
ssize_t mRepeat;
int32_t mToken;
ssize_t mIndex;
nsecs_t mNextStepTime;
+ void dumpPattern(std::string& dump) const;
void nextStep();
void stopVibrating();
};
diff --git a/services/inputflinger/tests/EventHub_test.cpp b/services/inputflinger/tests/EventHub_test.cpp
index 71731b0..ef68a84 100644
--- a/services/inputflinger/tests/EventHub_test.cpp
+++ b/services/inputflinger/tests/EventHub_test.cpp
@@ -199,3 +199,76 @@
lastEventTime = event.when; // Ensure all returned events are monotonic
}
}
+
+// --- BitArrayTest ---
+class BitArrayTest : public testing::Test {
+protected:
+ static constexpr size_t SINGLE_ELE_BITS = 32UL;
+ static constexpr size_t MULTI_ELE_BITS = 256UL;
+
+ virtual void SetUp() override {
+ mBitmaskSingle.loadFromBuffer(mBufferSingle);
+ mBitmaskMulti.loadFromBuffer(mBufferMulti);
+ }
+
+ android::BitArray<SINGLE_ELE_BITS> mBitmaskSingle;
+ android::BitArray<MULTI_ELE_BITS> mBitmaskMulti;
+
+private:
+ const typename android::BitArray<SINGLE_ELE_BITS>::Buffer mBufferSingle = {
+ 0x800F0F0FUL // bit 0 - 31
+ };
+ const typename android::BitArray<MULTI_ELE_BITS>::Buffer mBufferMulti = {
+ 0xFFFFFFFFUL, // bit 0 - 31
+ 0x01000001UL, // bit 32 - 63
+ 0x00000000UL, // bit 64 - 95
+ 0x80000000UL, // bit 96 - 127
+ 0x00000000UL, // bit 128 - 159
+ 0x00000000UL, // bit 160 - 191
+ 0x80000008UL, // bit 192 - 223
+ 0x00000000UL, // bit 224 - 255
+ };
+};
+
+TEST_F(BitArrayTest, SetBit) {
+ ASSERT_TRUE(mBitmaskSingle.test(0));
+ ASSERT_TRUE(mBitmaskSingle.test(31));
+ ASSERT_FALSE(mBitmaskSingle.test(7));
+
+ ASSERT_TRUE(mBitmaskMulti.test(32));
+ ASSERT_TRUE(mBitmaskMulti.test(56));
+ ASSERT_FALSE(mBitmaskMulti.test(192));
+ ASSERT_TRUE(mBitmaskMulti.test(223));
+ ASSERT_FALSE(mBitmaskMulti.test(255));
+}
+
+TEST_F(BitArrayTest, AnyBit) {
+ ASSERT_TRUE(mBitmaskSingle.any(31, 32));
+ ASSERT_FALSE(mBitmaskSingle.any(12, 16));
+
+ ASSERT_TRUE(mBitmaskMulti.any(31, 32));
+ ASSERT_FALSE(mBitmaskMulti.any(33, 33));
+ ASSERT_TRUE(mBitmaskMulti.any(32, 55));
+ ASSERT_TRUE(mBitmaskMulti.any(33, 57));
+ ASSERT_FALSE(mBitmaskMulti.any(33, 55));
+ ASSERT_FALSE(mBitmaskMulti.any(130, 190));
+
+ ASSERT_FALSE(mBitmaskMulti.any(128, 195));
+ ASSERT_TRUE(mBitmaskMulti.any(128, 196));
+ ASSERT_TRUE(mBitmaskMulti.any(128, 224));
+ ASSERT_FALSE(mBitmaskMulti.any(255, 256));
+}
+
+TEST_F(BitArrayTest, SetBit_InvalidBitIndex) {
+ ASSERT_FALSE(mBitmaskSingle.test(32));
+ ASSERT_FALSE(mBitmaskMulti.test(256));
+}
+
+TEST_F(BitArrayTest, AnyBit_InvalidBitIndex) {
+ ASSERT_FALSE(mBitmaskSingle.any(32, 32));
+ ASSERT_FALSE(mBitmaskSingle.any(33, 34));
+
+ ASSERT_FALSE(mBitmaskMulti.any(256, 256));
+ ASSERT_FALSE(mBitmaskMulti.any(257, 258));
+ ASSERT_FALSE(mBitmaskMulti.any(0, 0));
+}
diff --git a/services/inputflinger/tests/IInputFlingerQuery.aidl b/services/inputflinger/tests/IInputFlingerQuery.aidl
index 1edc089..755373b 100644
--- a/services/inputflinger/tests/IInputFlingerQuery.aidl
+++ b/services/inputflinger/tests/IInputFlingerQuery.aidl
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import android.InputChannelInfo;
+import android.InputChannel;
import android.InputWindowInfo;
import android.os.ISetInputWindowsListener;
@@ -23,5 +23,5 @@
{
/* Test interfaces */
void getInputWindows(out InputWindowInfo[] inputHandles);
- void getInputChannels(out InputChannelInfo[] infos);
+ void getInputChannels(out InputChannel[] channels);
}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index c749806..ce4d17d 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -602,7 +602,8 @@
class FakeInputReceiver {
public:
- explicit FakeInputReceiver(const sp<InputChannel>& clientChannel, const std::string name)
+ explicit FakeInputReceiver(const std::shared_ptr<InputChannel>& clientChannel,
+ const std::string name)
: mName(name) {
mConsumer = std::make_unique<InputConsumer>(clientChannel);
}
@@ -754,11 +755,11 @@
int32_t displayId, sp<IBinder> token = nullptr)
: mName(name) {
if (token == nullptr) {
- sp<InputChannel> serverChannel, clientChannel;
+ std::unique_ptr<InputChannel> serverChannel, clientChannel;
InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
- mInputReceiver = std::make_unique<FakeInputReceiver>(clientChannel, name);
- dispatcher->registerInputChannel(serverChannel);
+ mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(clientChannel), name);
token = serverChannel->getConnectionToken();
+ dispatcher->registerInputChannel(std::move(serverChannel));
}
inputApplicationHandle->updateInfo();
@@ -1767,10 +1768,10 @@
public:
FakeMonitorReceiver(const sp<InputDispatcher>& dispatcher, const std::string name,
int32_t displayId, bool isGestureMonitor = false) {
- sp<InputChannel> serverChannel, clientChannel;
+ std::unique_ptr<InputChannel> serverChannel, clientChannel;
InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
- mInputReceiver = std::make_unique<FakeInputReceiver>(clientChannel, name);
- dispatcher->registerInputMonitor(serverChannel, displayId, isGestureMonitor);
+ mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(clientChannel), name);
+ dispatcher->registerInputMonitor(std::move(serverChannel), displayId, isGestureMonitor);
}
sp<IBinder> getToken() { return mInputReceiver->getToken(); }
diff --git a/services/inputflinger/tests/InputFlingerService_test.cpp b/services/inputflinger/tests/InputFlingerService_test.cpp
index 193fe77..206e260 100644
--- a/services/inputflinger/tests/InputFlingerService_test.cpp
+++ b/services/inputflinger/tests/InputFlingerService_test.cpp
@@ -113,7 +113,7 @@
private:
sp<SetInputWindowsListener> mSetInputWindowsListener;
- sp<InputChannel> mServerChannel, mClientChannel;
+ std::unique_ptr<InputChannel> mServerChannel, mClientChannel;
InputWindowInfo mInfo;
std::mutex mLock;
std::condition_variable mSetInputWindowsFinishedCondition;
@@ -136,7 +136,7 @@
void checkFdFlags(const android::base::unique_fd& fd);
binder::Status getInputWindows(std::vector<::android::InputWindowInfo>* inputHandles);
- binder::Status getInputChannels(std::vector<::android::InputChannelInfo>* infos);
+ binder::Status getInputChannels(std::vector<::android::InputChannel>* channels);
status_t dump(int fd, const Vector<String16>& args) override;
@@ -144,20 +144,20 @@
const std::vector<InputWindowInfo>& handles,
const sp<ISetInputWindowsListener>& setInputWindowsListener) override;
- binder::Status registerInputChannel(const InputChannelInfo& channel) override;
- binder::Status unregisterInputChannel(const InputChannelInfo& channel) override;
+ binder::Status registerInputChannel(const InputChannel& channel) override;
+ binder::Status unregisterInputChannel(const InputChannel& channel) override;
private:
mutable Mutex mLock;
std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> mHandlesPerDisplay;
- std::vector<sp<InputChannel>> mInputChannels;
+ std::vector<std::shared_ptr<InputChannel>> mInputChannels;
};
class TestInputQuery : public BnInputFlingerQuery {
public:
TestInputQuery(sp<android::TestInputManager> manager) : mManager(manager){};
binder::Status getInputWindows(std::vector<::android::InputWindowInfo>* inputHandles) override;
- binder::Status getInputChannels(std::vector<::android::InputChannelInfo>* infos) override;
+ binder::Status getInputChannels(std::vector<::android::InputChannel>* channels) override;
private:
sp<android::TestInputManager> mManager;
@@ -168,8 +168,8 @@
return mManager->getInputWindows(inputHandles);
}
-binder::Status TestInputQuery::getInputChannels(std::vector<::android::InputChannelInfo>* infos) {
- return mManager->getInputChannels(infos);
+binder::Status TestInputQuery::getInputChannels(std::vector<::android::InputChannel>* channels) {
+ return mManager->getInputChannels(channels);
}
binder::Status SetInputWindowsListener::onSetInputWindowsFinished() {
@@ -200,27 +200,23 @@
EXPECT_EQ(result & O_NONBLOCK, O_NONBLOCK);
}
-binder::Status TestInputManager::registerInputChannel(const InputChannelInfo& info) {
+binder::Status TestInputManager::registerInputChannel(const InputChannel& channel) {
AutoMutex _l(mLock);
// check Fd flags
- checkFdFlags(info.mFd);
+ checkFdFlags(channel.getFd());
- android::base::unique_fd newFd(::dup(info.mFd));
- sp<InputChannel> channel = InputChannel::create(info.mName, std::move(newFd), info.mToken);
- mInputChannels.push_back(channel);
+ mInputChannels.push_back(channel.dup());
return binder::Status::ok();
}
-binder::Status TestInputManager::unregisterInputChannel(const InputChannelInfo& info) {
+binder::Status TestInputManager::unregisterInputChannel(const InputChannel& channel) {
AutoMutex _l(mLock);
// check Fd flags
- checkFdFlags(info.mFd);
- android::base::unique_fd newFd(::dup(info.mFd));
- sp<InputChannel> channel = InputChannel::create(info.mName, std::move(newFd), info.mToken);
+ checkFdFlags(channel.getFd());
auto it = std::find_if(mInputChannels.begin(), mInputChannels.end(),
- [&](sp<InputChannel>& it) { return *it == *channel; });
+ [&](std::shared_ptr<InputChannel>& c) { return *c == channel; });
if (it != mInputChannels.end()) {
mInputChannels.erase(it);
}
@@ -247,11 +243,10 @@
return binder::Status::ok();
}
-binder::Status TestInputManager::getInputChannels(std::vector<::android::InputChannelInfo>* infos) {
- infos->clear();
- for (auto& channel : mInputChannels) {
- auto chanDup = channel->dup();
- infos->push_back(std::move(chanDup->getInfo()));
+binder::Status TestInputManager::getInputChannels(std::vector<::android::InputChannel>* channels) {
+ channels->clear();
+ for (std::shared_ptr<InputChannel>& channel : mInputChannels) {
+ channels->push_back(*channel);
}
return binder::Status::ok();
}
@@ -320,12 +315,6 @@
mService->setInputWindows(infos, mSetInputWindowsListener);
// Verify listener call
EXPECT_NE(mSetInputWindowsFinishedCondition.wait_for(lock, 1s), std::cv_status::timeout);
- // Verify input windows from service
- std::vector<::android::InputWindowInfo> inputHandles;
- mQuery->getInputWindows(&inputHandles);
- for (auto& inputInfo : inputHandles) {
- verifyInputWindowInfo(inputInfo);
- }
}
/**
@@ -334,54 +323,57 @@
TEST_F(InputFlingerServiceTest, InputWindow_SetInputWindows) {
std::vector<InputWindowInfo> infos = {getInfo()};
setInputWindowsByInfos(infos);
+
+ // Verify input windows from service
+ std::vector<::android::InputWindowInfo> windowInfos;
+ mQuery->getInputWindows(&windowInfos);
+ for (const ::android::InputWindowInfo& windowInfo : windowInfos) {
+ verifyInputWindowInfo(windowInfo);
+ }
}
/**
* Test InputFlinger service interface registerInputChannel
*/
TEST_F(InputFlingerServiceTest, InputWindow_RegisterInputChannel) {
- sp<InputChannel> serverChannel, clientChannel;
+ std::unique_ptr<InputChannel> serverChannel, clientChannel;
InputChannel::openInputChannelPair("testchannels", serverChannel, clientChannel);
- mService->registerInputChannel(serverChannel->getInfo());
+ mService->registerInputChannel(*serverChannel);
- std::vector<::android::InputChannelInfo> infos(2);
- mQuery->getInputChannels(&infos);
- EXPECT_EQ(infos.size(), 1UL);
+ std::vector<::android::InputChannel> channels;
+ mQuery->getInputChannels(&channels);
+ ASSERT_EQ(channels.size(), 1UL);
+ EXPECT_EQ(channels[0], *serverChannel);
- auto& info = infos[0];
- android::base::unique_fd newFd(::dup(info.mFd));
- sp<InputChannel> channel = InputChannel::create(info.mName, std::move(newFd), info.mToken);
- EXPECT_EQ(*channel, *serverChannel);
-
- mService->unregisterInputChannel(serverChannel->getInfo());
- mQuery->getInputChannels(&infos);
- EXPECT_EQ(infos.size(), 0UL);
+ mService->unregisterInputChannel(*serverChannel);
+ mQuery->getInputChannels(&channels);
+ EXPECT_EQ(channels.size(), 0UL);
}
/**
* Test InputFlinger service interface registerInputChannel with invalid cases
*/
TEST_F(InputFlingerServiceTest, InputWindow_RegisterInputChannelInvalid) {
- sp<InputChannel> serverChannel, clientChannel;
+ std::unique_ptr<InputChannel> serverChannel, clientChannel;
InputChannel::openInputChannelPair("testchannels", serverChannel, clientChannel);
- std::vector<::android::InputChannelInfo> infos(2);
- mQuery->getInputChannels(&infos);
- EXPECT_EQ(infos.size(), 0UL);
+ std::vector<::android::InputChannel> channels;
+ mQuery->getInputChannels(&channels);
+ EXPECT_EQ(channels.size(), 0UL);
- mService->registerInputChannel(InputChannelInfo());
- mService->unregisterInputChannel(clientChannel->getInfo());
+ mService->registerInputChannel(InputChannel());
+ mService->unregisterInputChannel(*clientChannel);
- mService->registerInputChannel(serverChannel->getInfo());
- mService->registerInputChannel(clientChannel->getInfo());
- mQuery->getInputChannels(&infos);
- EXPECT_EQ(infos.size(), 2UL);
+ mService->registerInputChannel(*serverChannel);
+ mService->registerInputChannel(*clientChannel);
+ mQuery->getInputChannels(&channels);
+ EXPECT_EQ(channels.size(), 2UL);
- mService->unregisterInputChannel(clientChannel->getInfo());
- mService->unregisterInputChannel(serverChannel->getInfo());
- mQuery->getInputChannels(&infos);
- EXPECT_EQ(infos.size(), 0UL);
+ mService->unregisterInputChannel(*clientChannel);
+ mService->unregisterInputChannel(*serverChannel);
+ mQuery->getInputChannels(&channels);
+ EXPECT_EQ(channels.size(), 0UL);
}
} // namespace android
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index fae7e64..21dd3c7 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -45,16 +45,24 @@
static const nsecs_t ARBITRARY_TIME = 1234;
// Arbitrary display properties.
-static const int32_t DISPLAY_ID = 0;
-static const int32_t SECONDARY_DISPLAY_ID = DISPLAY_ID + 1;
-static const int32_t DISPLAY_WIDTH = 480;
-static const int32_t DISPLAY_HEIGHT = 800;
-static const int32_t VIRTUAL_DISPLAY_ID = 1;
-static const int32_t VIRTUAL_DISPLAY_WIDTH = 400;
-static const int32_t VIRTUAL_DISPLAY_HEIGHT = 500;
+static constexpr int32_t DISPLAY_ID = 0;
+static constexpr int32_t SECONDARY_DISPLAY_ID = DISPLAY_ID + 1;
+static constexpr int32_t DISPLAY_WIDTH = 480;
+static constexpr int32_t DISPLAY_HEIGHT = 800;
+static constexpr int32_t VIRTUAL_DISPLAY_ID = 1;
+static constexpr int32_t VIRTUAL_DISPLAY_WIDTH = 400;
+static constexpr int32_t VIRTUAL_DISPLAY_HEIGHT = 500;
static const char* VIRTUAL_DISPLAY_UNIQUE_ID = "virtual:1";
static constexpr std::optional<uint8_t> NO_PORT = std::nullopt; // no physical port is specified
+static constexpr int32_t FIRST_SLOT = 0;
+static constexpr int32_t SECOND_SLOT = 1;
+static constexpr int32_t THIRD_SLOT = 2;
+static constexpr int32_t INVALID_TRACKING_ID = -1;
+static constexpr int32_t FIRST_TRACKING_ID = 0;
+static constexpr int32_t SECOND_TRACKING_ID = 1;
+static constexpr int32_t THIRD_TRACKING_ID = 2;
+
// Error tolerance for floating point assertions.
static const float EPSILON = 0.001f;
@@ -813,8 +821,7 @@
return false;
}
- virtual void vibrate(int32_t, nsecs_t) {
- }
+ virtual void vibrate(int32_t, const VibrationElement&) {}
virtual void cancelVibrate(int32_t) {
}
@@ -1880,10 +1887,6 @@
// --- TouchProcessTest ---
class TouchIntegrationTest : public InputReaderIntegrationTest {
protected:
- static const int32_t FIRST_SLOT = 0;
- static const int32_t SECOND_SLOT = 1;
- static const int32_t FIRST_TRACKING_ID = 0;
- static const int32_t SECOND_TRACKING_ID = 1;
const std::string UNIQUE_ID = "local:0";
virtual void SetUp() override {
@@ -1954,9 +1957,9 @@
ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
// ACTION_POINTER_UP (Second slot)
- mDevice->sendUp();
+ mDevice->sendPointerUp();
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
args.action);
// ACTION_UP
@@ -1971,11 +1974,13 @@
const Point centerPoint = mDevice->getCenterPoint();
// ACTION_DOWN
+ mDevice->sendSlot(FIRST_SLOT);
+ mDevice->sendTrackingId(FIRST_TRACKING_ID);
mDevice->sendDown(centerPoint);
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
- // ACTION_POINTER_DOWN (Second slot)
+ // ACTION_POINTER_DOWN (second slot)
const Point secondPoint = centerPoint + Point(100, 100);
mDevice->sendSlot(SECOND_SLOT);
mDevice->sendTrackingId(SECOND_TRACKING_ID);
@@ -1984,26 +1989,31 @@
ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
args.action);
- // ACTION_MOVE (Second slot)
+ // ACTION_MOVE (second slot)
mDevice->sendMove(secondPoint + Point(1, 1));
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
- // Send MT_TOOL_PALM, which indicates that the touch IC has determined this to be a grip event.
- // Expect to receive ACTION_CANCEL, to abort the entire gesture.
+ // Send MT_TOOL_PALM (second slot), which indicates that the touch IC has determined this to be
+ // a palm event.
+ // Expect to receive the ACTION_POINTER_UP with cancel flag.
mDevice->sendToolType(MT_TOOL_PALM);
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
- ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, args.action);
+ ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ args.action);
+ ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, args.flags);
- // ACTION_POINTER_UP (Second slot)
- mDevice->sendUp();
+ // Send up to second slot, expect first slot send moving.
+ mDevice->sendPointerUp();
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
- // ACTION_UP
+ // Send ACTION_UP (first slot)
mDevice->sendSlot(FIRST_SLOT);
mDevice->sendUp();
- // Expect no event received after abort the entire gesture.
- ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled());
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action);
}
// --- InputDeviceTest ---
@@ -7064,10 +7074,10 @@
}
/**
- * Test touch should be canceled when received the MT_TOOL_PALM event, and the following MOVE and
- * UP events should be ignored.
+ * Test single touch should be canceled when received the MT_TOOL_PALM event, and the following
+ * MOVE and UP events should be ignored.
*/
-TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType) {
+TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_SinglePointer) {
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
@@ -7077,7 +7087,7 @@
// default tool type is finger
constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220, x3 = 140, y3 = 240;
- processId(mapper, 1);
+ processId(mapper, FIRST_TRACKING_ID);
processPosition(mapper, x1, y1);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
@@ -7091,19 +7101,19 @@
ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
// Ignore the following MOVE and UP events if had detect a palm event.
- processId(mapper, 1);
+ processId(mapper, FIRST_TRACKING_ID);
processPosition(mapper, x2, y2);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
// finger up.
- processId(mapper, -1);
+ processId(mapper, INVALID_TRACKING_ID);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
// new finger down
+ processId(mapper, FIRST_TRACKING_ID);
processToolType(mapper, MT_TOOL_FINGER);
- processId(mapper, 1);
processPosition(mapper, x3, y3);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
@@ -7112,11 +7122,10 @@
}
/**
- * Test multi-touch should be canceled when received the MT_TOOL_PALM event from some finger,
- * and could be allowed again after all non-MT_TOOL_PALM is release and the new point is
- * MT_TOOL_FINGER.
+ * Test multi-touch should sent POINTER_UP when received the MT_TOOL_PALM event from some finger,
+ * and the rest active fingers could still be allowed to receive the events
*/
-TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType2) {
+TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_TwoPointers) {
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
@@ -7125,8 +7134,8 @@
NotifyMotionArgs motionArgs;
// default tool type is finger
- constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220, x3 = 140, y3 = 240;
- processId(mapper, 1);
+ constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220;
+ processId(mapper, FIRST_TRACKING_ID);
processPosition(mapper, x1, y1);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
@@ -7134,51 +7143,232 @@
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
// Second finger down.
- processSlot(mapper, 1);
+ processSlot(mapper, SECOND_SLOT);
+ processId(mapper, SECOND_TRACKING_ID);
processPosition(mapper, x2, y2);
- processId(mapper, 2);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ motionArgs.action);
+ ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType);
+
+ // If the tool type of the first finger changes to MT_TOOL_PALM,
+ // we expect to receive ACTION_POINTER_UP with cancel flag.
+ processSlot(mapper, FIRST_SLOT);
+ processId(mapper, FIRST_TRACKING_ID);
+ processToolType(mapper, MT_TOOL_PALM);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ motionArgs.action);
+ ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
+
+ // The following MOVE events of second finger should be processed.
+ processSlot(mapper, SECOND_SLOT);
+ processId(mapper, SECOND_TRACKING_ID);
+ processPosition(mapper, x2 + 1, y2 + 1);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+ ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+ // First finger up. It used to be in palm mode, and we already generated ACTION_POINTER_UP for
+ // it. Second finger receive move.
+ processSlot(mapper, FIRST_SLOT);
+ processId(mapper, INVALID_TRACKING_ID);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+ ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+ // Second finger keeps moving.
+ processSlot(mapper, SECOND_SLOT);
+ processId(mapper, SECOND_TRACKING_ID);
+ processPosition(mapper, x2 + 2, y2 + 2);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+ ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+ // Second finger up.
+ processId(mapper, INVALID_TRACKING_ID);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
+ ASSERT_NE(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
+}
+
+/**
+ * Test multi-touch should sent POINTER_UP when received the MT_TOOL_PALM event, if only 1 finger
+ * is active, it should send CANCEL after receiving the MT_TOOL_PALM event.
+ */
+TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_ShouldCancelWhenAllTouchIsPalm) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+ NotifyMotionArgs motionArgs;
+
+ constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220, x3 = 140, y3 = 240;
+ // First finger down.
+ processId(mapper, FIRST_TRACKING_ID);
+ processPosition(mapper, x1, y1);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+ ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+
+ // Second finger down.
+ processSlot(mapper, SECOND_SLOT);
+ processId(mapper, SECOND_TRACKING_ID);
+ processPosition(mapper, x2, y2);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
- // If the tool type of the first pointer changes to MT_TOOL_PALM,
- // the entire gesture should be aborted, so we expect to receive ACTION_CANCEL.
- processSlot(mapper, 0);
- processId(mapper, 1);
+ // If the tool type of the first finger changes to MT_TOOL_PALM,
+ // we expect to receive ACTION_POINTER_UP with cancel flag.
+ processSlot(mapper, FIRST_SLOT);
+ processId(mapper, FIRST_TRACKING_ID);
+ processToolType(mapper, MT_TOOL_PALM);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ motionArgs.action);
+ ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
+
+ // Second finger keeps moving.
+ processSlot(mapper, SECOND_SLOT);
+ processId(mapper, SECOND_TRACKING_ID);
+ processPosition(mapper, x2 + 1, y2 + 1);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+
+ // second finger becomes palm, receive cancel due to only 1 finger is active.
+ processId(mapper, SECOND_TRACKING_ID);
processToolType(mapper, MT_TOOL_PALM);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
- // Ignore the following MOVE and UP events if had detect a palm event.
- processSlot(mapper, 1);
- processId(mapper, 2);
+ // third finger down.
+ processSlot(mapper, THIRD_SLOT);
+ processId(mapper, THIRD_TRACKING_ID);
+ processToolType(mapper, MT_TOOL_FINGER);
processPosition(mapper, x3, y3);
processSync(mapper);
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
-
- // second finger up.
- processId(mapper, -1);
- processSync(mapper);
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
-
- // first finger move, but still in palm
- processSlot(mapper, 0);
- processId(mapper, 1);
- processPosition(mapper, x1 - 1, y1 - 1);
- processSync(mapper);
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
-
- // second finger down, expect as new finger down.
- processSlot(mapper, 1);
- processId(mapper, 2);
- processPosition(mapper, x2, y2);
- processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+ ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+ // third finger move
+ processId(mapper, THIRD_TRACKING_ID);
+ processPosition(mapper, x3 + 1, y3 + 1);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+
+ // first finger up, third finger receive move.
+ processSlot(mapper, FIRST_SLOT);
+ processId(mapper, INVALID_TRACKING_ID);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+ ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+ // second finger up, third finger receive move.
+ processSlot(mapper, SECOND_SLOT);
+ processId(mapper, INVALID_TRACKING_ID);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+ ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+ // third finger up.
+ processSlot(mapper, THIRD_SLOT);
+ processId(mapper, INVALID_TRACKING_ID);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
+ ASSERT_NE(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
+}
+
+/**
+ * Test multi-touch should sent POINTER_UP when received the MT_TOOL_PALM event from some finger,
+ * and the active finger could still be allowed to receive the events
+ */
+TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_KeepFirstPointer) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+ NotifyMotionArgs motionArgs;
+
+ // default tool type is finger
+ constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220;
+ processId(mapper, FIRST_TRACKING_ID);
+ processPosition(mapper, x1, y1);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+ ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+
+ // Second finger down.
+ processSlot(mapper, SECOND_SLOT);
+ processId(mapper, SECOND_TRACKING_ID);
+ processPosition(mapper, x2, y2);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ motionArgs.action);
+ ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+
+ // If the tool type of the second finger changes to MT_TOOL_PALM,
+ // we expect to receive ACTION_POINTER_UP with cancel flag.
+ processId(mapper, SECOND_TRACKING_ID);
+ processToolType(mapper, MT_TOOL_PALM);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ motionArgs.action);
+ ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
+
+ // The following MOVE event should be processed.
+ processSlot(mapper, FIRST_SLOT);
+ processId(mapper, FIRST_TRACKING_ID);
+ processPosition(mapper, x1 + 1, y1 + 1);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+ ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+ // second finger up.
+ processSlot(mapper, SECOND_SLOT);
+ processId(mapper, INVALID_TRACKING_ID);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+
+ // first finger keep moving
+ processSlot(mapper, FIRST_SLOT);
+ processId(mapper, FIRST_TRACKING_ID);
+ processPosition(mapper, x1 + 2, y1 + 2);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+
+ // first finger up.
+ processId(mapper, INVALID_TRACKING_ID);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
+ ASSERT_NE(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
}
// --- MultiTouchInputMapperTest_ExternalDevice ---
diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp
index 0659511..7fec2c8 100644
--- a/services/inputflinger/tests/UinputDevice.cpp
+++ b/services/inputflinger/tests/UinputDevice.cpp
@@ -179,6 +179,11 @@
injectEvent(EV_SYN, SYN_REPORT, 0);
}
+void UinputTouchScreen::sendPointerUp() {
+ sendTrackingId(0xffffffff);
+ injectEvent(EV_SYN, SYN_REPORT, 0);
+}
+
void UinputTouchScreen::sendUp() {
sendTrackingId(0xffffffff);
injectEvent(EV_KEY, BTN_TOUCH, 0);
diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h
index 22d1f63..01a557c 100644
--- a/services/inputflinger/tests/UinputDevice.h
+++ b/services/inputflinger/tests/UinputDevice.h
@@ -139,6 +139,7 @@
void sendTrackingId(int32_t trackingId);
void sendDown(const Point& point);
void sendMove(const Point& point);
+ void sendPointerUp();
void sendUp();
void sendToolType(int32_t toolType);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 8dd4b0a..b53e2dc 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -61,36 +61,46 @@
} while (false)
namespace android {
+
namespace {
-std::unique_ptr<DispSync> createDispSync(bool supportKernelTimer) {
- // TODO (140302863) remove this and use the vsync_reactor system.
- if (property_get_bool("debug.sf.vsync_reactor", true)) {
+std::unique_ptr<scheduler::VSyncTracker> createVSyncTracker() {
+ // TODO (144707443) tune Predictor tunables.
+ static constexpr int default_rate = 60;
+ static constexpr auto initial_period =
+ std::chrono::duration<nsecs_t, std::ratio<1, default_rate>>(1);
+ static constexpr size_t vsyncTimestampHistorySize = 20;
+ static constexpr size_t minimumSamplesForPrediction = 6;
+ static constexpr uint32_t discardOutlierPercent = 20;
+ return std::make_unique<
+ scheduler::VSyncPredictor>(std::chrono::duration_cast<std::chrono::nanoseconds>(
+ initial_period)
+ .count(),
+ vsyncTimestampHistorySize, minimumSamplesForPrediction,
+ discardOutlierPercent);
+}
+
+std::unique_ptr<scheduler::VSyncDispatch> createVSyncDispatch(
+ const std::unique_ptr<scheduler::VSyncTracker>& vSyncTracker) {
+ if (!vSyncTracker) return {};
+
+ // TODO (144707443) tune Predictor tunables.
+ static constexpr auto vsyncMoveThreshold =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(3ms);
+ static constexpr auto timerSlack = std::chrono::duration_cast<std::chrono::nanoseconds>(500us);
+ return std::make_unique<
+ scheduler::VSyncDispatchTimerQueue>(std::make_unique<scheduler::Timer>(), *vSyncTracker,
+ timerSlack.count(), vsyncMoveThreshold.count());
+}
+
+std::unique_ptr<DispSync> createDispSync(
+ const std::unique_ptr<scheduler::VSyncTracker>& vSyncTracker,
+ const std::unique_ptr<scheduler::VSyncDispatch>& vSyncDispatch, bool supportKernelTimer) {
+ if (vSyncTracker && vSyncDispatch) {
// TODO (144707443) tune Predictor tunables.
- static constexpr int defaultRate = 60;
- static constexpr auto initialPeriod =
- std::chrono::duration<nsecs_t, std::ratio<1, defaultRate>>(1);
- static constexpr size_t vsyncTimestampHistorySize = 20;
- static constexpr size_t minimumSamplesForPrediction = 6;
- static constexpr uint32_t discardOutlierPercent = 20;
- auto tracker = std::make_unique<
- scheduler::VSyncPredictor>(std::chrono::duration_cast<std::chrono::nanoseconds>(
- initialPeriod)
- .count(),
- vsyncTimestampHistorySize, minimumSamplesForPrediction,
- discardOutlierPercent);
-
- static constexpr auto vsyncMoveThreshold =
- std::chrono::duration_cast<std::chrono::nanoseconds>(3ms);
- static constexpr auto timerSlack =
- std::chrono::duration_cast<std::chrono::nanoseconds>(500us);
- auto dispatch = std::make_unique<
- scheduler::VSyncDispatchTimerQueue>(std::make_unique<scheduler::Timer>(), *tracker,
- timerSlack.count(), vsyncMoveThreshold.count());
-
static constexpr size_t pendingFenceLimit = 20;
return std::make_unique<scheduler::VSyncReactor>(std::make_unique<scheduler::SystemClock>(),
- std::move(dispatch), std::move(tracker),
+ *vSyncDispatch, *vSyncTracker,
pendingFenceLimit, supportKernelTimer);
} else {
return std::make_unique<impl::DispSync>("SchedulerDispSync",
@@ -110,7 +120,11 @@
ISchedulerCallback& schedulerCallback, bool useContentDetectionV2,
bool useContentDetection)
: mSupportKernelTimer(sysprop::support_kernel_idle_timer(false)),
- mPrimaryDispSync(createDispSync(mSupportKernelTimer)),
+ // TODO (140302863) remove this and use the vsync_reactor system.
+ mUseVsyncPredictor(property_get_bool("debug.sf.vsync_reactor", true)),
+ mVSyncTracker(mUseVsyncPredictor ? createVSyncTracker() : nullptr),
+ mVSyncDispatch(createVSyncDispatch(mVSyncTracker)),
+ mPrimaryDispSync(createDispSync(mVSyncTracker, mVSyncDispatch, mSupportKernelTimer)),
mEventControlThread(new impl::EventControlThread(std::move(function))),
mLayerHistory(createLayerHistory(refreshRateConfigs, useContentDetectionV2)),
mSchedulerCallback(schedulerCallback),
@@ -156,6 +170,7 @@
std::unique_ptr<LayerHistory> layerHistory, bool useContentDetectionV2,
bool useContentDetection)
: mSupportKernelTimer(false),
+ mUseVsyncPredictor(true),
mPrimaryDispSync(std::move(primaryDispSync)),
mEventControlThread(std::move(eventControlThread)),
mLayerHistory(std::move(layerHistory)),
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 5fee4b4..2fe5629 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -44,7 +44,11 @@
class DispSync;
class FenceTime;
class InjectVSyncSource;
-struct DisplayStateInfo;
+
+namespace scheduler {
+class VSyncDispatch;
+class VSyncTracker;
+} // namespace scheduler
class ISchedulerCallback {
public:
@@ -230,6 +234,9 @@
// Whether to use idle timer callbacks that support the kernel timer.
const bool mSupportKernelTimer;
+ const bool mUseVsyncPredictor;
+ const std::unique_ptr<scheduler::VSyncTracker> mVSyncTracker;
+ const std::unique_ptr<scheduler::VSyncDispatch> mVSyncDispatch;
std::unique_ptr<DispSync> mPrimaryDispSync;
std::unique_ptr<EventControlThread> mEventControlThread;
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index efa8bab..a2b279b 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -55,15 +55,15 @@
}
};
-VSyncReactor::VSyncReactor(std::unique_ptr<Clock> clock, std::unique_ptr<VSyncDispatch> dispatch,
- std::unique_ptr<VSyncTracker> tracker, size_t pendingFenceLimit,
+VSyncReactor::VSyncReactor(std::unique_ptr<Clock> clock, VSyncDispatch& dispatch,
+ VSyncTracker& tracker, size_t pendingFenceLimit,
bool supportKernelIdleTimer)
: mClock(std::move(clock)),
- mTracker(std::move(tracker)),
- mDispatch(std::move(dispatch)),
+ mTracker(tracker),
+ mDispatch(dispatch),
mPendingLimit(pendingFenceLimit),
mPredictedVsyncTracer(property_get_bool("debug.sf.show_predicted_vsync", false)
- ? std::make_unique<PredictedVsyncTracer>(*mDispatch)
+ ? std::make_unique<PredictedVsyncTracer>(mDispatch)
: nullptr),
mSupportKernelIdleTimer(supportKernelIdleTimer) {}
@@ -182,7 +182,7 @@
} else if (time == Fence::SIGNAL_TIME_INVALID) {
it = mUnfiredFences.erase(it);
} else {
- timestampAccepted &= mTracker->addVsyncTimestamp(time);
+ timestampAccepted &= mTracker.addVsyncTimestamp(time);
it = mUnfiredFences.erase(it);
}
@@ -194,7 +194,7 @@
}
mUnfiredFences.push_back(fence);
} else {
- timestampAccepted &= mTracker->addVsyncTimestamp(signalTime);
+ timestampAccepted &= mTracker.addVsyncTimestamp(signalTime);
}
if (!timestampAccepted) {
@@ -224,12 +224,12 @@
}
nsecs_t VSyncReactor::computeNextRefresh(int periodOffset, nsecs_t now) const {
- auto const currentPeriod = periodOffset ? mTracker->currentPeriod() : 0;
- return mTracker->nextAnticipatedVSyncTimeFrom(now + periodOffset * currentPeriod);
+ auto const currentPeriod = periodOffset ? mTracker.currentPeriod() : 0;
+ return mTracker.nextAnticipatedVSyncTimeFrom(now + periodOffset * currentPeriod);
}
nsecs_t VSyncReactor::expectedPresentTime(nsecs_t now) {
- return mTracker->nextAnticipatedVSyncTimeFrom(now);
+ return mTracker.nextAnticipatedVSyncTimeFrom(now);
}
void VSyncReactor::startPeriodTransition(nsecs_t newPeriod) {
@@ -262,11 +262,11 @@
}
nsecs_t VSyncReactor::getPeriod() {
- return mTracker->currentPeriod();
+ return mTracker.currentPeriod();
}
void VSyncReactor::beginResync() {
- mTracker->resetModel();
+ mTracker.resetModel();
}
void VSyncReactor::endResync() {}
@@ -307,7 +307,7 @@
if (periodConfirmed(timestamp, hwcVsyncPeriod)) {
ATRACE_NAME("VSR: period confirmed");
if (mPeriodTransitioningTo) {
- mTracker->setPeriod(*mPeriodTransitioningTo);
+ mTracker.setPeriod(*mPeriodTransitioningTo);
for (auto& entry : mCallbacks) {
entry.second->setPeriod(*mPeriodTransitioningTo);
}
@@ -315,12 +315,12 @@
}
if (mLastHwVsync) {
- mTracker->addVsyncTimestamp(*mLastHwVsync);
+ mTracker.addVsyncTimestamp(*mLastHwVsync);
}
- mTracker->addVsyncTimestamp(timestamp);
+ mTracker.addVsyncTimestamp(timestamp);
endPeriodTransition();
- mMoreSamplesNeeded = mTracker->needsMoreSamples();
+ mMoreSamplesNeeded = mTracker.needsMoreSamples();
} else if (mPeriodConfirmationInProgress) {
ATRACE_NAME("VSR: still confirming period");
mLastHwVsync = timestamp;
@@ -329,8 +329,8 @@
} else {
ATRACE_NAME("VSR: adding sample");
*periodFlushed = false;
- mTracker->addVsyncTimestamp(timestamp);
- mMoreSamplesNeeded = mTracker->needsMoreSamples();
+ mTracker.addVsyncTimestamp(timestamp);
+ mMoreSamplesNeeded = mTracker.needsMoreSamples();
}
if (!mMoreSamplesNeeded) {
@@ -353,9 +353,9 @@
return NO_MEMORY;
}
- auto const period = mTracker->currentPeriod();
- auto repeater = std::make_unique<CallbackRepeater>(*mDispatch, callback, name, period,
- phase, mClock->now());
+ auto const period = mTracker.currentPeriod();
+ auto repeater = std::make_unique<CallbackRepeater>(mDispatch, callback, name, period, phase,
+ mClock->now());
it = mCallbacks.emplace(std::pair(callback, std::move(repeater))).first;
}
@@ -409,9 +409,9 @@
}
StringAppendF(&result, "VSyncTracker:\n");
- mTracker->dump(result);
+ mTracker.dump(result);
StringAppendF(&result, "VSyncDispatch:\n");
- mDispatch->dump(result);
+ mDispatch.dump(result);
}
void VSyncReactor::reset() {}
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h
index 265d89c..22ceb39 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.h
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.h
@@ -35,9 +35,8 @@
// TODO (b/145217110): consider renaming.
class VSyncReactor : public android::DispSync {
public:
- VSyncReactor(std::unique_ptr<Clock> clock, std::unique_ptr<VSyncDispatch> dispatch,
- std::unique_ptr<VSyncTracker> tracker, size_t pendingFenceLimit,
- bool supportKernelIdleTimer);
+ VSyncReactor(std::unique_ptr<Clock> clock, VSyncDispatch& dispatch, VSyncTracker& tracker,
+ size_t pendingFenceLimit, bool supportKernelIdleTimer);
~VSyncReactor();
bool addPresentFence(const std::shared_ptr<FenceTime>& fence) final;
@@ -72,8 +71,8 @@
REQUIRES(mMutex);
std::unique_ptr<Clock> const mClock;
- std::unique_ptr<VSyncTracker> const mTracker;
- std::unique_ptr<VSyncDispatch> const mDispatch;
+ VSyncTracker& mTracker;
+ VSyncDispatch& mDispatch;
size_t const mPendingLimit;
mutable std::mutex mMutex;
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 6856612..c5cddf3 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -45,26 +45,6 @@
MOCK_CONST_METHOD1(dump, void(std::string&));
};
-class VSyncTrackerWrapper : public VSyncTracker {
-public:
- VSyncTrackerWrapper(std::shared_ptr<VSyncTracker> const& tracker) : mTracker(tracker) {}
-
- bool addVsyncTimestamp(nsecs_t timestamp) final {
- return mTracker->addVsyncTimestamp(timestamp);
- }
- nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final {
- return mTracker->nextAnticipatedVSyncTimeFrom(timePoint);
- }
- nsecs_t currentPeriod() const final { return mTracker->currentPeriod(); }
- void setPeriod(nsecs_t period) final { mTracker->setPeriod(period); }
- void resetModel() final { mTracker->resetModel(); }
- bool needsMoreSamples() const final { return mTracker->needsMoreSamples(); }
- void dump(std::string& result) const final { mTracker->dump(result); }
-
-private:
- std::shared_ptr<VSyncTracker> const mTracker;
-};
-
class MockClock : public Clock {
public:
MOCK_CONST_METHOD0(now, nsecs_t());
@@ -90,29 +70,6 @@
MOCK_CONST_METHOD1(dump, void(std::string&));
};
-class VSyncDispatchWrapper : public VSyncDispatch {
-public:
- VSyncDispatchWrapper(std::shared_ptr<VSyncDispatch> const& dispatch) : mDispatch(dispatch) {}
- CallbackToken registerCallback(std::function<void(nsecs_t, nsecs_t)> const& callbackFn,
- std::string callbackName) final {
- return mDispatch->registerCallback(callbackFn, callbackName);
- }
-
- void unregisterCallback(CallbackToken token) final { mDispatch->unregisterCallback(token); }
-
- ScheduleResult schedule(CallbackToken token, nsecs_t workDuration,
- nsecs_t earliestVsync) final {
- return mDispatch->schedule(token, workDuration, earliestVsync);
- }
-
- CancelResult cancel(CallbackToken token) final { return mDispatch->cancel(token); }
-
- void dump(std::string& result) const final { return mDispatch->dump(result); }
-
-private:
- std::shared_ptr<VSyncDispatch> const mDispatch;
-};
-
std::shared_ptr<FenceTime> generateInvalidFence() {
sp<Fence> fence = new Fence();
return std::make_shared<FenceTime>(fence);
@@ -157,10 +114,8 @@
: mMockDispatch(std::make_shared<NiceMock<MockVSyncDispatch>>()),
mMockTracker(std::make_shared<NiceMock<MockVSyncTracker>>()),
mMockClock(std::make_shared<NiceMock<MockClock>>()),
- mReactor(std::make_unique<ClockWrapper>(mMockClock),
- std::make_unique<VSyncDispatchWrapper>(mMockDispatch),
- std::make_unique<VSyncTrackerWrapper>(mMockTracker), kPendingLimit,
- false /* supportKernelIdleTimer */) {
+ mReactor(std::make_unique<ClockWrapper>(mMockClock), *mMockDispatch, *mMockTracker,
+ kPendingLimit, false /* supportKernelIdleTimer */) {
ON_CALL(*mMockClock, now()).WillByDefault(Return(mFakeNow));
ON_CALL(*mMockTracker, currentPeriod()).WillByDefault(Return(period));
}
@@ -745,10 +700,9 @@
TEST_F(VSyncReactorTest, periodIsMeasuredIfIgnoringComposer) {
// Create a reactor which supports the kernel idle timer
- auto idleReactor = VSyncReactor(std::make_unique<ClockWrapper>(mMockClock),
- std::make_unique<VSyncDispatchWrapper>(mMockDispatch),
- std::make_unique<VSyncTrackerWrapper>(mMockTracker),
- kPendingLimit, true /* supportKernelIdleTimer */);
+ auto idleReactor =
+ VSyncReactor(std::make_unique<ClockWrapper>(mMockClock), *mMockDispatch, *mMockTracker,
+ kPendingLimit, true /* supportKernelIdleTimer */);
bool periodFlushed = true;
EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(4);