Fade out the mouse pointer after inactivity or other events.
Fades out the mouse pointer: - after 15 seconds of inactivity normally - after 3 seconds of inactivity in lights out mode - after a non-modifier key down - after a touch down Extended the native Looper to support enqueuing time delayed messages. This is used by the PointerController to control pointer fade timing. Change-Id: I87792fea7dbe2d9376c78cf354fe3189a484d9da
This commit is contained in:
parent
76048aeee7
commit
80f3e7cc15
@ -51,6 +51,14 @@ enum {
|
||||
AINPUT_SOURCE_SWITCH = 0x80000000,
|
||||
};
|
||||
|
||||
/*
|
||||
* SystemUiVisibility constants from View.
|
||||
*/
|
||||
enum {
|
||||
ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE = 0,
|
||||
ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN = 0x00000001,
|
||||
};
|
||||
|
||||
/*
|
||||
* Maximum number of pointers supported per motion event.
|
||||
* Smallest number of pointers is 1.
|
||||
|
@ -127,6 +127,11 @@ extern const char* getAxisLabel(int32_t axisId);
|
||||
*/
|
||||
extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState);
|
||||
|
||||
/**
|
||||
* Returns true if a key is a meta key like ALT or CAPS_LOCK.
|
||||
*/
|
||||
extern bool isMetaKey(int32_t keyCode);
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // _UI_KEYBOARD_H
|
||||
|
@ -44,6 +44,51 @@ struct ALooper {
|
||||
|
||||
namespace android {
|
||||
|
||||
/**
|
||||
* A message that can be posted to a Looper.
|
||||
*/
|
||||
struct Message {
|
||||
Message() : what(0) { }
|
||||
Message(int what) : what(what) { }
|
||||
|
||||
/* The message type. (interpretation is left up to the handler) */
|
||||
int what;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Interface for a Looper message handler.
|
||||
*
|
||||
* The Looper holds a strong reference to the message handler whenever it has
|
||||
* a message to deliver to it. Make sure to call Looper::removeMessages
|
||||
* to remove any pending messages destined for the handler so that the handler
|
||||
* can be destroyed.
|
||||
*/
|
||||
class MessageHandler : public virtual RefBase {
|
||||
protected:
|
||||
virtual ~MessageHandler() { }
|
||||
|
||||
public:
|
||||
/**
|
||||
* Handles a message.
|
||||
*/
|
||||
virtual void handleMessage(const Message& message) = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A simple proxy that holds a weak reference to a message handler.
|
||||
*/
|
||||
class WeakMessageHandler : public MessageHandler {
|
||||
public:
|
||||
WeakMessageHandler(const wp<MessageHandler>& handler);
|
||||
virtual void handleMessage(const Message& message);
|
||||
|
||||
private:
|
||||
wp<MessageHandler> mHandler;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A polling loop that supports monitoring file descriptor events, optionally
|
||||
* using callbacks. The implementation uses epoll() internally.
|
||||
@ -165,6 +210,52 @@ public:
|
||||
*/
|
||||
int removeFd(int fd);
|
||||
|
||||
/**
|
||||
* Enqueues a message to be processed by the specified handler.
|
||||
*
|
||||
* The handler must not be null.
|
||||
* This method can be called on any thread.
|
||||
*/
|
||||
void sendMessage(const sp<MessageHandler>& handler, const Message& message);
|
||||
|
||||
/**
|
||||
* Enqueues a message to be processed by the specified handler after all pending messages
|
||||
* after the specified delay.
|
||||
*
|
||||
* The time delay is specified in uptime nanoseconds.
|
||||
* The handler must not be null.
|
||||
* This method can be called on any thread.
|
||||
*/
|
||||
void sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
|
||||
const Message& message);
|
||||
|
||||
/**
|
||||
* Enqueues a message to be processed by the specified handler after all pending messages
|
||||
* at the specified time.
|
||||
*
|
||||
* The time is specified in uptime nanoseconds.
|
||||
* The handler must not be null.
|
||||
* This method can be called on any thread.
|
||||
*/
|
||||
void sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
|
||||
const Message& message);
|
||||
|
||||
/**
|
||||
* Removes all messages for the specified handler from the queue.
|
||||
*
|
||||
* The handler must not be null.
|
||||
* This method can be called on any thread.
|
||||
*/
|
||||
void removeMessages(const sp<MessageHandler>& handler);
|
||||
|
||||
/**
|
||||
* Removes all messages of a particular type for the specified handler from the queue.
|
||||
*
|
||||
* The handler must not be null.
|
||||
* This method can be called on any thread.
|
||||
*/
|
||||
void removeMessages(const sp<MessageHandler>& handler, int what);
|
||||
|
||||
/**
|
||||
* Prepares a looper associated with the calling thread, and returns it.
|
||||
* If the thread already has a looper, it is returned. Otherwise, a new
|
||||
@ -201,12 +292,27 @@ private:
|
||||
Request request;
|
||||
};
|
||||
|
||||
struct MessageEnvelope {
|
||||
MessageEnvelope() : uptime(0) { }
|
||||
|
||||
MessageEnvelope(nsecs_t uptime, const sp<MessageHandler> handler,
|
||||
const Message& message) : uptime(uptime), handler(handler), message(message) {
|
||||
}
|
||||
|
||||
nsecs_t uptime;
|
||||
sp<MessageHandler> handler;
|
||||
Message message;
|
||||
};
|
||||
|
||||
const bool mAllowNonCallbacks; // immutable
|
||||
|
||||
int mWakeReadPipeFd; // immutable
|
||||
int mWakeWritePipeFd; // immutable
|
||||
Mutex mLock;
|
||||
|
||||
Vector<MessageEnvelope> mMessageEnvelopes; // guarded by mLock
|
||||
bool mSendingMessage; // guarded by mLock
|
||||
|
||||
#ifdef LOOPER_USES_EPOLL
|
||||
int mEpollFd; // immutable
|
||||
|
||||
@ -256,6 +362,7 @@ private:
|
||||
// it runs on a single thread.
|
||||
Vector<Response> mResponses;
|
||||
size_t mResponseIndex;
|
||||
nsecs_t mNextMessageUptime; // set to LLONG_MAX when none
|
||||
|
||||
int pollInner(int timeoutMillis);
|
||||
void awoken();
|
||||
|
@ -322,5 +322,26 @@ int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
|
||||
}
|
||||
}
|
||||
|
||||
bool isMetaKey(int32_t keyCode) {
|
||||
switch (keyCode) {
|
||||
case AKEYCODE_ALT_LEFT:
|
||||
case AKEYCODE_ALT_RIGHT:
|
||||
case AKEYCODE_SHIFT_LEFT:
|
||||
case AKEYCODE_SHIFT_RIGHT:
|
||||
case AKEYCODE_SYM:
|
||||
case AKEYCODE_FUNCTION:
|
||||
case AKEYCODE_CTRL_LEFT:
|
||||
case AKEYCODE_CTRL_RIGHT:
|
||||
case AKEYCODE_META_LEFT:
|
||||
case AKEYCODE_META_RIGHT:
|
||||
case AKEYCODE_CAPS_LOCK:
|
||||
case AKEYCODE_NUM_LOCK:
|
||||
case AKEYCODE_SCROLL_LOCK:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace android
|
||||
|
@ -19,10 +19,27 @@
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
namespace android {
|
||||
|
||||
// --- WeakMessageHandler ---
|
||||
|
||||
WeakMessageHandler::WeakMessageHandler(const wp<MessageHandler>& handler) :
|
||||
mHandler(handler) {
|
||||
}
|
||||
|
||||
void WeakMessageHandler::handleMessage(const Message& message) {
|
||||
sp<MessageHandler> handler = mHandler.promote();
|
||||
if (handler != NULL) {
|
||||
handler->handleMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- Looper ---
|
||||
|
||||
#ifdef LOOPER_USES_EPOLL
|
||||
// Hint for number of file descriptors to be associated with the epoll instance.
|
||||
static const int EPOLL_SIZE_HINT = 8;
|
||||
@ -35,8 +52,8 @@ static pthread_once_t gTLSOnce = PTHREAD_ONCE_INIT;
|
||||
static pthread_key_t gTLSKey = 0;
|
||||
|
||||
Looper::Looper(bool allowNonCallbacks) :
|
||||
mAllowNonCallbacks(allowNonCallbacks),
|
||||
mResponseIndex(0) {
|
||||
mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
|
||||
mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
|
||||
int wakeFds[2];
|
||||
int result = pipe(wakeFds);
|
||||
LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
|
||||
@ -161,17 +178,21 @@ int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outDa
|
||||
for (;;) {
|
||||
while (mResponseIndex < mResponses.size()) {
|
||||
const Response& response = mResponses.itemAt(mResponseIndex++);
|
||||
if (! response.request.callback) {
|
||||
ALooper_callbackFunc callback = response.request.callback;
|
||||
if (!callback) {
|
||||
int ident = response.request.ident;
|
||||
int fd = response.request.fd;
|
||||
int events = response.events;
|
||||
void* data = response.request.data;
|
||||
#if DEBUG_POLL_AND_WAKE
|
||||
LOGD("%p ~ pollOnce - returning signalled identifier %d: "
|
||||
"fd=%d, events=0x%x, data=%p", this,
|
||||
response.request.ident, response.request.fd,
|
||||
response.events, response.request.data);
|
||||
"fd=%d, events=0x%x, data=%p",
|
||||
this, ident, fd, events, data);
|
||||
#endif
|
||||
if (outFd != NULL) *outFd = response.request.fd;
|
||||
if (outEvents != NULL) *outEvents = response.events;
|
||||
if (outData != NULL) *outData = response.request.data;
|
||||
return response.request.ident;
|
||||
if (outFd != NULL) *outFd = fd;
|
||||
if (outEvents != NULL) *outEvents = events;
|
||||
if (outData != NULL) *outData = data;
|
||||
return ident;
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,6 +215,25 @@ int Looper::pollInner(int timeoutMillis) {
|
||||
LOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
|
||||
#endif
|
||||
|
||||
// Adjust the timeout based on when the next message is due.
|
||||
if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
|
||||
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
if (mNextMessageUptime <= now) {
|
||||
timeoutMillis = 0;
|
||||
} else {
|
||||
uint64_t delay = (mNextMessageUptime - now + 999999LL) / 1000000LL;
|
||||
if (delay < INT_MAX
|
||||
&& (timeoutMillis < 0 || int(delay) < timeoutMillis)) {
|
||||
timeoutMillis = int(delay);
|
||||
}
|
||||
}
|
||||
#if DEBUG_POLL_AND_WAKE
|
||||
LOGD("%p ~ pollOnce - next message in %lldns, adjusted timeout: timeoutMillis=%d",
|
||||
this, mNextMessageUptime - now, timeoutMillis);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Poll.
|
||||
int result = ALOOPER_POLL_WAKE;
|
||||
mResponses.clear();
|
||||
mResponseIndex = 0;
|
||||
@ -205,7 +245,6 @@ int Looper::pollInner(int timeoutMillis) {
|
||||
#ifdef LOOPER_USES_EPOLL
|
||||
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
|
||||
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
|
||||
bool acquiredLock = false;
|
||||
#else
|
||||
// Wait for wakeAndLock() waiters to run then set mPolling to true.
|
||||
mLock.lock();
|
||||
@ -219,16 +258,20 @@ int Looper::pollInner(int timeoutMillis) {
|
||||
int eventCount = poll(mRequestedFds.editArray(), requestedCount, timeoutMillis);
|
||||
#endif
|
||||
|
||||
// Acquire lock.
|
||||
mLock.lock();
|
||||
|
||||
// Check for poll error.
|
||||
if (eventCount < 0) {
|
||||
if (errno == EINTR) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
LOGW("Poll failed with an unexpected error, errno=%d", errno);
|
||||
result = ALOOPER_POLL_ERROR;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// Check for poll timeout.
|
||||
if (eventCount == 0) {
|
||||
#if DEBUG_POLL_AND_WAKE
|
||||
LOGD("%p ~ pollOnce - timeout", this);
|
||||
@ -237,6 +280,7 @@ int Looper::pollInner(int timeoutMillis) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// Handle all events.
|
||||
#if DEBUG_POLL_AND_WAKE
|
||||
LOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);
|
||||
#endif
|
||||
@ -252,11 +296,6 @@ int Looper::pollInner(int timeoutMillis) {
|
||||
LOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);
|
||||
}
|
||||
} else {
|
||||
if (! acquiredLock) {
|
||||
mLock.lock();
|
||||
acquiredLock = true;
|
||||
}
|
||||
|
||||
ssize_t requestIndex = mRequests.indexOfKey(fd);
|
||||
if (requestIndex >= 0) {
|
||||
int events = 0;
|
||||
@ -271,9 +310,6 @@ int Looper::pollInner(int timeoutMillis) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (acquiredLock) {
|
||||
mLock.unlock();
|
||||
}
|
||||
Done: ;
|
||||
#else
|
||||
for (size_t i = 0; i < requestedCount; i++) {
|
||||
@ -301,15 +337,12 @@ Done: ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Done:
|
||||
// Set mPolling to false and wake up the wakeAndLock() waiters.
|
||||
mLock.lock();
|
||||
mPolling = false;
|
||||
if (mWaiters != 0) {
|
||||
mAwake.broadcast();
|
||||
}
|
||||
mLock.unlock();
|
||||
#endif
|
||||
|
||||
#ifdef LOOPER_STATISTICS
|
||||
@ -335,19 +368,59 @@ Done:
|
||||
}
|
||||
#endif
|
||||
|
||||
// Invoke pending message callbacks.
|
||||
mNextMessageUptime = LLONG_MAX;
|
||||
while (mMessageEnvelopes.size() != 0) {
|
||||
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
|
||||
if (messageEnvelope.uptime <= now) {
|
||||
// Remove the envelope from the list.
|
||||
// We keep a strong reference to the handler until the call to handleMessage
|
||||
// finishes. Then we drop it so that the handler can be deleted *before*
|
||||
// we reacquire our lock.
|
||||
{ // obtain handler
|
||||
sp<MessageHandler> handler = messageEnvelope.handler;
|
||||
Message message = messageEnvelope.message;
|
||||
mMessageEnvelopes.removeAt(0);
|
||||
mSendingMessage = true;
|
||||
mLock.unlock();
|
||||
|
||||
#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
|
||||
LOGD("%p ~ pollOnce - sending message: handler=%p, what=%d",
|
||||
this, handler.get(), message.what);
|
||||
#endif
|
||||
handler->handleMessage(message);
|
||||
} // release handler
|
||||
|
||||
mLock.lock();
|
||||
mSendingMessage = false;
|
||||
result = ALOOPER_POLL_CALLBACK;
|
||||
} else {
|
||||
// The last message left at the head of the queue determines the next wakeup time.
|
||||
mNextMessageUptime = messageEnvelope.uptime;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Release lock.
|
||||
mLock.unlock();
|
||||
|
||||
// Invoke all response callbacks.
|
||||
for (size_t i = 0; i < mResponses.size(); i++) {
|
||||
const Response& response = mResponses.itemAt(i);
|
||||
if (response.request.callback) {
|
||||
ALooper_callbackFunc callback = response.request.callback;
|
||||
if (callback) {
|
||||
int fd = response.request.fd;
|
||||
int events = response.events;
|
||||
void* data = response.request.data;
|
||||
#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
|
||||
LOGD("%p ~ pollOnce - invoking callback: fd=%d, events=0x%x, data=%p", this,
|
||||
response.request.fd, response.events, response.request.data);
|
||||
LOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p",
|
||||
this, callback, fd, events, data);
|
||||
#endif
|
||||
int callbackResult = response.request.callback(
|
||||
response.request.fd, response.events, response.request.data);
|
||||
int callbackResult = callback(fd, events, data);
|
||||
if (callbackResult == 0) {
|
||||
removeFd(response.request.fd);
|
||||
removeFd(fd);
|
||||
}
|
||||
|
||||
result = ALOOPER_POLL_CALLBACK;
|
||||
}
|
||||
}
|
||||
@ -593,4 +666,83 @@ void Looper::wakeAndLock() {
|
||||
}
|
||||
#endif
|
||||
|
||||
void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) {
|
||||
sendMessageAtTime(LLONG_MIN, handler, message);
|
||||
}
|
||||
|
||||
void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
|
||||
const Message& message) {
|
||||
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
sendMessageAtTime(now + uptimeDelay, handler, message);
|
||||
}
|
||||
|
||||
void Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
|
||||
const Message& message) {
|
||||
#if DEBUG_CALLBACKS
|
||||
LOGD("%p ~ sendMessageAtTime - uptime=%lld, handler=%p, what=%d",
|
||||
this, uptime, handler.get(), message.what);
|
||||
#endif
|
||||
|
||||
size_t i = 0;
|
||||
{ // acquire lock
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
size_t messageCount = mMessageEnvelopes.size();
|
||||
while (i < messageCount && uptime >= mMessageEnvelopes.itemAt(i).uptime) {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
MessageEnvelope messageEnvelope(uptime, handler, message);
|
||||
mMessageEnvelopes.insertAt(messageEnvelope, i, 1);
|
||||
|
||||
// Optimization: If the Looper is currently sending a message, then we can skip
|
||||
// the call to wake() because the next thing the Looper will do after processing
|
||||
// messages is to decide when the next wakeup time should be. In fact, it does
|
||||
// not even matter whether this code is running on the Looper thread.
|
||||
if (mSendingMessage) {
|
||||
return;
|
||||
}
|
||||
} // release lock
|
||||
|
||||
// Wake the poll loop only when we enqueue a new message at the head.
|
||||
if (i == 0) {
|
||||
wake();
|
||||
}
|
||||
}
|
||||
|
||||
void Looper::removeMessages(const sp<MessageHandler>& handler) {
|
||||
#if DEBUG_CALLBACKS
|
||||
LOGD("%p ~ removeMessages - handler=%p", this, handler.get());
|
||||
#endif
|
||||
|
||||
{ // acquire lock
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
for (size_t i = mMessageEnvelopes.size(); i != 0; ) {
|
||||
const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(--i);
|
||||
if (messageEnvelope.handler == handler) {
|
||||
mMessageEnvelopes.removeAt(i);
|
||||
}
|
||||
}
|
||||
} // release lock
|
||||
}
|
||||
|
||||
void Looper::removeMessages(const sp<MessageHandler>& handler, int what) {
|
||||
#if DEBUG_CALLBACKS
|
||||
LOGD("%p ~ removeMessages - handler=%p, what=%d", this, handler.get(), what);
|
||||
#endif
|
||||
|
||||
{ // acquire lock
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
for (size_t i = mMessageEnvelopes.size(); i != 0; ) {
|
||||
const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(--i);
|
||||
if (messageEnvelope.handler == handler
|
||||
&& messageEnvelope.message.what == what) {
|
||||
mMessageEnvelopes.removeAt(i);
|
||||
}
|
||||
}
|
||||
} // release lock
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
@ -16,6 +16,13 @@
|
||||
|
||||
namespace android {
|
||||
|
||||
enum {
|
||||
MSG_TEST1 = 1,
|
||||
MSG_TEST2 = 2,
|
||||
MSG_TEST3 = 3,
|
||||
MSG_TEST4 = 4,
|
||||
};
|
||||
|
||||
class DelayedWake : public DelayedTask {
|
||||
sp<Looper> mLooper;
|
||||
|
||||
@ -82,6 +89,15 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
class StubMessageHandler : public MessageHandler {
|
||||
public:
|
||||
Vector<Message> messages;
|
||||
|
||||
virtual void handleMessage(const Message& message) {
|
||||
messages.push(message);
|
||||
}
|
||||
};
|
||||
|
||||
class LooperTest : public testing::Test {
|
||||
protected:
|
||||
sp<Looper> mLooper;
|
||||
@ -421,5 +437,257 @@ TEST_F(LooperTest, PollOnce_WhenCallbackAddedTwice_OnlySecondCallbackShouldBeInv
|
||||
<< "replacement handler callback should be invoked";
|
||||
}
|
||||
|
||||
TEST_F(LooperTest, SendMessage_WhenOneMessageIsEnqueue_ShouldInvokeHandlerDuringNextPoll) {
|
||||
sp<StubMessageHandler> handler = new StubMessageHandler();
|
||||
mLooper->sendMessage(handler, Message(MSG_TEST1));
|
||||
|
||||
StopWatch stopWatch("pollOnce");
|
||||
int result = mLooper->pollOnce(100);
|
||||
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
|
||||
|
||||
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
|
||||
<< "elapsed time should approx. zero because message was already sent";
|
||||
EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
|
||||
<< "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
|
||||
EXPECT_EQ(size_t(1), handler->messages.size())
|
||||
<< "handled message";
|
||||
EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
|
||||
<< "handled message";
|
||||
}
|
||||
|
||||
TEST_F(LooperTest, SendMessage_WhenMultipleMessagesAreEnqueued_ShouldInvokeHandlersInOrderDuringNextPoll) {
|
||||
sp<StubMessageHandler> handler1 = new StubMessageHandler();
|
||||
sp<StubMessageHandler> handler2 = new StubMessageHandler();
|
||||
mLooper->sendMessage(handler1, Message(MSG_TEST1));
|
||||
mLooper->sendMessage(handler2, Message(MSG_TEST2));
|
||||
mLooper->sendMessage(handler1, Message(MSG_TEST3));
|
||||
mLooper->sendMessage(handler1, Message(MSG_TEST4));
|
||||
|
||||
StopWatch stopWatch("pollOnce");
|
||||
int result = mLooper->pollOnce(1000);
|
||||
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
|
||||
|
||||
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
|
||||
<< "elapsed time should approx. zero because message was already sent";
|
||||
EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
|
||||
<< "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
|
||||
EXPECT_EQ(size_t(3), handler1->messages.size())
|
||||
<< "handled message";
|
||||
EXPECT_EQ(MSG_TEST1, handler1->messages[0].what)
|
||||
<< "handled message";
|
||||
EXPECT_EQ(MSG_TEST3, handler1->messages[1].what)
|
||||
<< "handled message";
|
||||
EXPECT_EQ(MSG_TEST4, handler1->messages[2].what)
|
||||
<< "handled message";
|
||||
EXPECT_EQ(size_t(1), handler2->messages.size())
|
||||
<< "handled message";
|
||||
EXPECT_EQ(MSG_TEST2, handler2->messages[0].what)
|
||||
<< "handled message";
|
||||
}
|
||||
|
||||
TEST_F(LooperTest, SendMessageDelayed_WhenSentToTheFuture_ShouldInvokeHandlerAfterDelayTime) {
|
||||
sp<StubMessageHandler> handler = new StubMessageHandler();
|
||||
mLooper->sendMessageDelayed(ms2ns(100), handler, Message(MSG_TEST1));
|
||||
|
||||
StopWatch stopWatch("pollOnce");
|
||||
int result = mLooper->pollOnce(1000);
|
||||
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
|
||||
|
||||
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
|
||||
<< "first poll should end quickly because next message timeout was computed";
|
||||
EXPECT_EQ(ALOOPER_POLL_WAKE, result)
|
||||
<< "pollOnce result should be ALOOPER_POLL_WAKE due to wakeup";
|
||||
EXPECT_EQ(size_t(0), handler->messages.size())
|
||||
<< "no message handled yet";
|
||||
|
||||
result = mLooper->pollOnce(1000);
|
||||
elapsedMillis = ns2ms(stopWatch.elapsedTime());
|
||||
|
||||
EXPECT_EQ(size_t(1), handler->messages.size())
|
||||
<< "handled message";
|
||||
EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
|
||||
<< "handled message";
|
||||
EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
|
||||
<< "second poll should end around the time of the delayed message dispatch";
|
||||
EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
|
||||
<< "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
|
||||
|
||||
result = mLooper->pollOnce(100);
|
||||
elapsedMillis = ns2ms(stopWatch.elapsedTime());
|
||||
|
||||
EXPECT_NEAR(100 + 100, elapsedMillis, TIMING_TOLERANCE_MS)
|
||||
<< "third poll should timeout";
|
||||
EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
|
||||
<< "pollOnce result should be ALOOPER_POLL_TIMEOUT because there were no messages left";
|
||||
}
|
||||
|
||||
TEST_F(LooperTest, SendMessageDelayed_WhenSentToThePast_ShouldInvokeHandlerDuringNextPoll) {
|
||||
sp<StubMessageHandler> handler = new StubMessageHandler();
|
||||
mLooper->sendMessageDelayed(ms2ns(-1000), handler, Message(MSG_TEST1));
|
||||
|
||||
StopWatch stopWatch("pollOnce");
|
||||
int result = mLooper->pollOnce(100);
|
||||
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
|
||||
|
||||
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
|
||||
<< "elapsed time should approx. zero because message was already sent";
|
||||
EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
|
||||
<< "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
|
||||
EXPECT_EQ(size_t(1), handler->messages.size())
|
||||
<< "handled message";
|
||||
EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
|
||||
<< "handled message";
|
||||
}
|
||||
|
||||
TEST_F(LooperTest, SendMessageDelayed_WhenSentToThePresent_ShouldInvokeHandlerDuringNextPoll) {
|
||||
sp<StubMessageHandler> handler = new StubMessageHandler();
|
||||
mLooper->sendMessageDelayed(0, handler, Message(MSG_TEST1));
|
||||
|
||||
StopWatch stopWatch("pollOnce");
|
||||
int result = mLooper->pollOnce(100);
|
||||
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
|
||||
|
||||
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
|
||||
<< "elapsed time should approx. zero because message was already sent";
|
||||
EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
|
||||
<< "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
|
||||
EXPECT_EQ(size_t(1), handler->messages.size())
|
||||
<< "handled message";
|
||||
EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
|
||||
<< "handled message";
|
||||
}
|
||||
|
||||
TEST_F(LooperTest, SendMessageAtTime_WhenSentToTheFuture_ShouldInvokeHandlerAfterDelayTime) {
|
||||
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
sp<StubMessageHandler> handler = new StubMessageHandler();
|
||||
mLooper->sendMessageAtTime(now + ms2ns(100), handler, Message(MSG_TEST1));
|
||||
|
||||
StopWatch stopWatch("pollOnce");
|
||||
int result = mLooper->pollOnce(1000);
|
||||
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
|
||||
|
||||
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
|
||||
<< "first poll should end quickly because next message timeout was computed";
|
||||
EXPECT_EQ(ALOOPER_POLL_WAKE, result)
|
||||
<< "pollOnce result should be ALOOPER_POLL_WAKE due to wakeup";
|
||||
EXPECT_EQ(size_t(0), handler->messages.size())
|
||||
<< "no message handled yet";
|
||||
|
||||
result = mLooper->pollOnce(1000);
|
||||
elapsedMillis = ns2ms(stopWatch.elapsedTime());
|
||||
|
||||
EXPECT_EQ(size_t(1), handler->messages.size())
|
||||
<< "handled message";
|
||||
EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
|
||||
<< "handled message";
|
||||
EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
|
||||
<< "second poll should end around the time of the delayed message dispatch";
|
||||
EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
|
||||
<< "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
|
||||
|
||||
result = mLooper->pollOnce(100);
|
||||
elapsedMillis = ns2ms(stopWatch.elapsedTime());
|
||||
|
||||
EXPECT_NEAR(100 + 100, elapsedMillis, TIMING_TOLERANCE_MS)
|
||||
<< "third poll should timeout";
|
||||
EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
|
||||
<< "pollOnce result should be ALOOPER_POLL_TIMEOUT because there were no messages left";
|
||||
}
|
||||
|
||||
TEST_F(LooperTest, SendMessageAtTime_WhenSentToThePast_ShouldInvokeHandlerDuringNextPoll) {
|
||||
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
sp<StubMessageHandler> handler = new StubMessageHandler();
|
||||
mLooper->sendMessageAtTime(now - ms2ns(1000), handler, Message(MSG_TEST1));
|
||||
|
||||
StopWatch stopWatch("pollOnce");
|
||||
int result = mLooper->pollOnce(100);
|
||||
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
|
||||
|
||||
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
|
||||
<< "elapsed time should approx. zero because message was already sent";
|
||||
EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
|
||||
<< "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
|
||||
EXPECT_EQ(size_t(1), handler->messages.size())
|
||||
<< "handled message";
|
||||
EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
|
||||
<< "handled message";
|
||||
}
|
||||
|
||||
TEST_F(LooperTest, SendMessageAtTime_WhenSentToThePresent_ShouldInvokeHandlerDuringNextPoll) {
|
||||
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
sp<StubMessageHandler> handler = new StubMessageHandler();
|
||||
mLooper->sendMessageAtTime(now, handler, Message(MSG_TEST1));
|
||||
|
||||
StopWatch stopWatch("pollOnce");
|
||||
int result = mLooper->pollOnce(100);
|
||||
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
|
||||
|
||||
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
|
||||
<< "elapsed time should approx. zero because message was already sent";
|
||||
EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
|
||||
<< "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
|
||||
EXPECT_EQ(size_t(1), handler->messages.size())
|
||||
<< "handled message";
|
||||
EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
|
||||
<< "handled message";
|
||||
}
|
||||
|
||||
TEST_F(LooperTest, RemoveMessage_WhenRemovingAllMessagesForHandler_ShouldRemoveThoseMessage) {
|
||||
sp<StubMessageHandler> handler = new StubMessageHandler();
|
||||
mLooper->sendMessage(handler, Message(MSG_TEST1));
|
||||
mLooper->sendMessage(handler, Message(MSG_TEST2));
|
||||
mLooper->sendMessage(handler, Message(MSG_TEST3));
|
||||
mLooper->removeMessages(handler);
|
||||
|
||||
StopWatch stopWatch("pollOnce");
|
||||
int result = mLooper->pollOnce(0);
|
||||
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
|
||||
|
||||
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
|
||||
<< "elapsed time should approx. zero because message was sent so looper was awoken";
|
||||
EXPECT_EQ(ALOOPER_POLL_WAKE, result)
|
||||
<< "pollOnce result should be ALOOPER_POLL_WAKE because looper was awoken";
|
||||
EXPECT_EQ(size_t(0), handler->messages.size())
|
||||
<< "no messages to handle";
|
||||
|
||||
result = mLooper->pollOnce(0);
|
||||
|
||||
EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
|
||||
<< "pollOnce result should be ALOOPER_POLL_TIMEOUT because there was nothing to do";
|
||||
EXPECT_EQ(size_t(0), handler->messages.size())
|
||||
<< "no messages to handle";
|
||||
}
|
||||
|
||||
TEST_F(LooperTest, RemoveMessage_WhenRemovingSomeMessagesForHandler_ShouldRemoveThoseMessage) {
|
||||
sp<StubMessageHandler> handler = new StubMessageHandler();
|
||||
mLooper->sendMessage(handler, Message(MSG_TEST1));
|
||||
mLooper->sendMessage(handler, Message(MSG_TEST2));
|
||||
mLooper->sendMessage(handler, Message(MSG_TEST3));
|
||||
mLooper->sendMessage(handler, Message(MSG_TEST4));
|
||||
mLooper->removeMessages(handler, MSG_TEST3);
|
||||
mLooper->removeMessages(handler, MSG_TEST1);
|
||||
|
||||
StopWatch stopWatch("pollOnce");
|
||||
int result = mLooper->pollOnce(0);
|
||||
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
|
||||
|
||||
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
|
||||
<< "elapsed time should approx. zero because message was sent so looper was awoken";
|
||||
EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
|
||||
<< "pollOnce result should be ALOOPER_POLL_CALLBACK because two messages were sent";
|
||||
EXPECT_EQ(size_t(2), handler->messages.size())
|
||||
<< "no messages to handle";
|
||||
EXPECT_EQ(MSG_TEST2, handler->messages[0].what)
|
||||
<< "handled message";
|
||||
EXPECT_EQ(MSG_TEST4, handler->messages[1].what)
|
||||
<< "handled message";
|
||||
|
||||
result = mLooper->pollOnce(0);
|
||||
|
||||
EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
|
||||
<< "pollOnce result should be ALOOPER_POLL_TIMEOUT because there was nothing to do";
|
||||
EXPECT_EQ(size_t(2), handler->messages.size())
|
||||
<< "no more messages to handle";
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
Loading…
Reference in New Issue
Block a user