103 lines
3.6 KiB
C
103 lines
3.6 KiB
C
|
|
#pragma once
|
||
|
|
|
||
|
|
#include <freertos/FreeRTOS.h>
|
||
|
|
#include <freertos/semphr.h>
|
||
|
|
#include <freertos/task.h>
|
||
|
|
|
||
|
|
#include <cassert>
|
||
|
|
#include <memory>
|
||
|
|
#include <string>
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
|
#include "GfxRenderer.h"
|
||
|
|
#include "MappedInputManager.h"
|
||
|
|
#include "RenderLock.h"
|
||
|
|
|
||
|
|
class Activity; // forward declaration
|
||
|
|
class RenderLock; // forward declaration
|
||
|
|
|
||
|
|
/**
|
||
|
|
* ActivityManager
|
||
|
|
*
|
||
|
|
* This mirrors the same concept of Activity in Android, where an activity represents a single screen of the UI. The
|
||
|
|
* manager is responsible for launching activities, and ensuring that only one activity is active at a time.
|
||
|
|
*
|
||
|
|
* It also provides a stack mechanism to allow activities to launch sub-activities and get back the results when the
|
||
|
|
* sub-activity is done. For example, the WebServer activity can launch a WifiSelect activity to let the user choose a
|
||
|
|
* wifi network, and get back the selected network when the user is done.
|
||
|
|
*
|
||
|
|
* Main differences from Android's ActivityManager:
|
||
|
|
* - No onPause/onResume, since we don't have a concept of background activities
|
||
|
|
* - onActivityResult is implemented via a callback instead of a separate method, for simplicity
|
||
|
|
*/
|
||
|
|
class ActivityManager {
|
||
|
|
protected:
|
||
|
|
GfxRenderer& renderer;
|
||
|
|
MappedInputManager& mappedInput;
|
||
|
|
std::vector<std::unique_ptr<Activity>> stackActivities;
|
||
|
|
std::unique_ptr<Activity> currentActivity;
|
||
|
|
|
||
|
|
void exitActivity(const RenderLock& lock);
|
||
|
|
|
||
|
|
// Pending activity to be launched on next loop iteration
|
||
|
|
std::unique_ptr<Activity> pendingActivity;
|
||
|
|
enum class PendingAction { None, Push, Pop, Replace };
|
||
|
|
PendingAction pendingAction = PendingAction::None;
|
||
|
|
|
||
|
|
// Task to render and display the activity
|
||
|
|
TaskHandle_t renderTaskHandle = nullptr;
|
||
|
|
static void renderTaskTrampoline(void* param);
|
||
|
|
[[noreturn]] virtual void renderTaskLoop();
|
||
|
|
|
||
|
|
// Whether to trigger a render after the current loop()
|
||
|
|
// This variable must only be set by the main loop, to avoid race conditions
|
||
|
|
bool requestedUpdate = false;
|
||
|
|
|
||
|
|
public:
|
||
|
|
explicit ActivityManager(GfxRenderer& renderer, MappedInputManager& mappedInput)
|
||
|
|
: renderer(renderer), mappedInput(mappedInput), renderingMutex(xSemaphoreCreateMutex()) {
|
||
|
|
assert(renderingMutex != nullptr && "Failed to create rendering mutex");
|
||
|
|
stackActivities.reserve(10);
|
||
|
|
}
|
||
|
|
~ActivityManager() { assert(false); /* should never be called */ };
|
||
|
|
|
||
|
|
// Mutex to protect rendering operations from race conditions
|
||
|
|
// Must only be used via RenderLock
|
||
|
|
SemaphoreHandle_t renderingMutex = nullptr;
|
||
|
|
|
||
|
|
void begin();
|
||
|
|
void loop();
|
||
|
|
|
||
|
|
// Will replace currentActivity and drop all activities on stack
|
||
|
|
void replaceActivity(std::unique_ptr<Activity>&& newActivity);
|
||
|
|
|
||
|
|
// goTo... functions are convenient wrapper for replaceActivity()
|
||
|
|
void goToFileTransfer();
|
||
|
|
void goToSettings();
|
||
|
|
void goToMyLibrary(std::string path = {});
|
||
|
|
void goToRecentBooks();
|
||
|
|
void goToBrowser();
|
||
|
|
void goToReader(std::string path);
|
||
|
|
void goToSleep();
|
||
|
|
void goToBoot();
|
||
|
|
void goToFullScreenMessage(std::string message, EpdFontFamily::Style style = EpdFontFamily::REGULAR);
|
||
|
|
void goHome();
|
||
|
|
|
||
|
|
// This will move current activity to stack instead of deleting it
|
||
|
|
void pushActivity(std::unique_ptr<Activity>&& activity);
|
||
|
|
|
||
|
|
// Remove the currentActivity, returning the last one on stack
|
||
|
|
// Note: if popActivity() on last activity on the stack, we will goHome()
|
||
|
|
void popActivity();
|
||
|
|
|
||
|
|
bool preventAutoSleep() const;
|
||
|
|
bool isReaderActivity() const;
|
||
|
|
bool skipLoopDelay() const;
|
||
|
|
|
||
|
|
// If immediate is true, the update will be triggered immediately.
|
||
|
|
// Otherwise, it will be deferred until the end of the current loop iteration.
|
||
|
|
void requestUpdate(bool immediate = false);
|
||
|
|
};
|
||
|
|
|
||
|
|
extern ActivityManager activityManager; // singleton, to be defined in main.cpp
|