blob: 2ee7369fc03c3f248a6ae3a0e239bb2dc5f0d3ec [file] [log] [blame]
// Copyright 2015 The Android Open Source Project
//
// This software is licensed under the terms of the GNU General Public
// License version 2, as published by the Free Software Foundation, and
// may be copied, distributed, and modified under those terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#include "android/skin/qt/QtLooper.h"
#include "android/base/containers/ScopedPointerSet.h"
#include "android/base/containers/TailQueueList.h"
#include "android/skin/qt/QtTimerImpl.h"
#include <QTime>
namespace android {
namespace qt {
namespace internal {
typedef ::android::base::Looper BaseLooper;
typedef ::android::base::Looper::Timer BaseTimer;
typedef ::android::base::Looper::FdWatch BaseFdWatch;
// A partial implementation of android::base::Looper on top of the Qt main
// event loop. There are few important things here:
//
// 1/ There is a single global Qt event loop per thread. So, all instances
// returned by createLooper() will really use the same state on a thread!
//
// In other words, don't call it more than once per thread!
//
// 2/ It is not possible to call the runWithDeadlineMs() method, since
// the event loop is started in the application's main thread by
// the executable.
//
// 3/ Clock implementation is limited
// - Millisecond precision only.
// - Only ClockType::kHost is supported.
//
// 4/ FdWatch is not implemented yet (as it's not in use yet).
class QtLooper : public BaseLooper {
public:
QtLooper() : Looper() {}
//
// T I M E R S
//
// The underlying timer is of Qt::TimerType Qt::CoarseTimer. This gives us
// almost millisecond accuracy (5% error margin), but is more efficient.
class Timer : public BaseTimer {
public:
virtual void startRelative(Duration timeout_ms) {
if (timeout_ms == kDurationInfinite) {
mTimer.stop();
} else {
mTimer.start(timeout_ms);
}
}
virtual void startAbsolute(Duration deadline_ms) {
Q_ASSERT_X(false, "QtLooper::Timer::startAbsolute",
"startAbsolute is not supported.");
}
virtual void stop() { mTimer.stop(); }
virtual bool isActive() const { return mTimer.isActive(); }
virtual void save(android::base::Stream* stream) const {
qDebug("QtLooper::Timer does not support serialization. Skipped.");
}
virtual void load(android::base::Stream* stream) {
qDebug("QtLooper::Timer does not support deserialization. "
"Skipped.");
}
protected:
// |QtLooper| provides method(s) to construct an object of this kind.
friend class QtLooper;
Timer(QtLooper* looper,
BaseTimer::Callback callback,
void* opaque,
ClockType clock)
: BaseTimer(looper, callback, opaque, clock),
mTimer(callback, opaque, this) {
mTimer.setSingleShot(true);
}
private:
TimerImpl mTimer;
DISALLOW_COPY_AND_ASSIGN(Timer);
};
virtual BaseTimer* createTimer(BaseTimer::Callback callback,
void* opaque,
ClockType clock) {
clock = validateClockType(clock);
return new QtLooper::Timer(this, callback, opaque, clock);
}
virtual BaseFdWatch* createFdWatch(int fd,
BaseFdWatch::Callback callback,
void* opaque) {
Q_ASSERT_X(false, "QtLooper::createFdWatch",
"FdWatch is not yet implemented for QtLooper.");
return nullptr;
}
//
// L O O P E R
//
virtual Duration nowMs(ClockType clock) {
clock = validateClockType(clock);
auto time = QTime::currentTime();
return time.msec() +
1000UL * (time.second() +
60UL * (time.minute() + 60UL * time.hour()));
}
virtual DurationNs nowNs(ClockType clockType) {
qWarning("QtLooper::nowNs is not supported. Defaulting to nowMs.");
return nowMs(clockType);
}
virtual int runWithDeadlineMs(Duration deadline_ms) {
qWarning("User cannot call |run*| on a QtLooper event loop");
errno = ENOSYS;
return -1;
}
virtual void forceQuit() {
qWarning("User cannot call |forceQuit| on a QtLooper event loop");
}
protected:
ClockType validateClockType(ClockType clock) {
if (clock != ClockType::kHost) {
qWarning(
"QtLooper::Timer does not support %s."
"Defaulting to ClockType::kHost.",
Looper::clockTypeToString(clock));
}
return ClockType::kHost;
}
private:
DISALLOW_COPY_AND_ASSIGN(QtLooper);
};
} // namespace internal
android::base::Looper* createLooper() {
return new internal::QtLooper();
}
} // namespace qt
} // namespace android