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:
Jeff Brown 2011-03-02 14:41:58 -08:00
parent 76048aeee7
commit 80f3e7cc15
6 changed files with 591 additions and 30 deletions

View File

@ -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.

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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