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