blob: 08d03f8eeb23689ef06b4fbbbf9537af3040259b [file] [log] [blame]
// Copyright (C) 2015 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.
#pragma once
#include "android/base/async/Looper.h"
#include "android/base/Compiler.h"
#include <functional>
#include <memory>
namespace android {
namespace base {
// A RecurrentTask is an object that allows you to run a task repeatedly on the
// event loop, until you're done.
// Example:
//
// class AreWeThereYet {
// public:
// AreWeThereYet(Looper* looper) :
// mAskRepeatedly(looper,
// std::bind(&AreWeThereYet::askAgain),
// 1 * 60 * 1000) {}
//
// void askAgain() {
// std::cout << "Are we there yet?" << std::endl;
// }
//
// void startHike() {
// mAskRepeatedly.start();
// }
//
// private:
// RecurrentTask mAskRepeatedly;
// };
//
// Note: RecurrentTask is meant to execute a task __on the looper thread__.
// It is not thread safe.
class RecurrentTask {
public:
using TaskFunction = std::function<bool()>;
RecurrentTask(Looper* looper,
TaskFunction function,
Looper::Duration taskIntervalMs) :
mLooper(looper), mFunction(function), mTaskIntervalMs(taskIntervalMs),
mTimer(mLooper->createTimer(&RecurrentTask::taskCallback, this)) {}
~RecurrentTask() {
stop();
}
void start() {
stop();
mInFlight = true;
mTimer->startRelative(mTaskIntervalMs);
}
void stop() {
mInFlight = false;
if(mTimer) {
mTimer->stop();
}
}
bool inFlight() {
return mInFlight;
}
protected:
static void taskCallback(void* opaqueThis, Looper::Timer* timer) {
auto thisPtr = static_cast<RecurrentTask*>(opaqueThis);
if (!thisPtr->mFunction()) {
thisPtr->mInFlight = false;
return;
}
// It is possible that the client code in |mFunction| calls |stop|, so
// we must double check before reposting the task.
if (thisPtr->mInFlight) {
thisPtr->mTimer->startRelative(thisPtr->mTaskIntervalMs);
}
}
private:
Looper* mLooper;
TaskFunction mFunction;
Looper::Duration mTaskIntervalMs;
std::unique_ptr<Looper::Timer> mTimer;
bool mInFlight = false;
};
} // namespace base
} // namespace android