#pragma once #include #include #include #include #include #include #include #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> stackActivities; std::unique_ptr currentActivity; void exitActivity(const RenderLock& lock); // Pending activity to be launched on next loop iteration std::unique_ptr 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&& 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); // 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