diff --git a/designer/main.cpp b/designer/main.cpp index 60c9749..1ea508b 100644 --- a/designer/main.cpp +++ b/designer/main.cpp @@ -810,6 +810,19 @@ bool InitializeRmlUi(const std::string& assets_path, int fb_width, int fb_height std::cout << "goHome called - returning to home screen" << std::endl; + // Reset sandbox back to home context + if (g_sandbox && !g_current_app_id.empty()) { + g_sandbox->UnregisterAPIs(L); + g_sandbox->Reset(); + + mosis::DesktopSandboxConfig config; + config.app_id = "com.mosis.home"; + config.data_root = g_main_assets_path + "/sandbox_data"; + g_sandbox = std::make_unique(config); + g_sandbox->RegisterAPIs(L); + std::cout << "Sandbox reset to home context" << std::endl; + } + // Close existing documents (except debugger) while (g_context->GetNumDocuments() > 1) { auto* doc = g_context->GetDocument(0); @@ -839,7 +852,36 @@ bool InitializeRmlUi(const std::string& assets_path, int fb_width, int fb_height return 1; }); lua_setglobal(L, "goHome"); - std::cout << "Registered Lua loadScreen and goHome functions" << std::endl; + + // Register switchAppSandbox function for third-party app launching + lua_pushcfunction(L, [](lua_State* L) -> int { + const char* app_id = luaL_checkstring(L, 1); + const char* install_path = luaL_checkstring(L, 2); + + std::cout << "switchAppSandbox called for: " << app_id << " at " << install_path << std::endl; + + // Store current app ID + g_current_app_id = app_id; + + // Reset sandbox for the new app + if (g_sandbox) { + g_sandbox->UnregisterAPIs(L); + g_sandbox->Reset(); + + // Re-configure sandbox with app-specific data root + mosis::DesktopSandboxConfig config; + config.app_id = app_id; + config.data_root = std::string(install_path) + "/sandbox_data"; + g_sandbox = std::make_unique(config); + g_sandbox->RegisterAPIs(L); + std::cout << "Sandbox switched to: " << app_id << std::endl; + } + + lua_pushboolean(L, true); + return 1; + }); + lua_setglobal(L, "switchAppSandbox"); + std::cout << "Registered Lua loadScreen, goHome, and switchAppSandbox functions" << std::endl; // Register simulator API (if in simulator mode) if (g_simulator_mode) { diff --git a/src/main/assets/apps/home/home.lua b/src/main/assets/apps/home/home.lua index 176f8ae..82c8f1d 100644 --- a/src/main/assets/apps/home/home.lua +++ b/src/main/assets/apps/home/home.lua @@ -110,10 +110,22 @@ function renderThirdPartyApps() -- Check if app has an icon if app.icon and app.icon ~= "" then - -- Third-party app icon path would be in their install directory - -- For now, use initial as we need file:// protocol support - icon_html = '' .. initial .. '' + local icon_path + -- Check if icon is already a full path (starts with / or contains :/) + if app.icon:sub(1, 1) == "/" or app.icon:find(":/") then + -- Already a full path + icon_path = app.icon + elseif app.install_path and app.install_path ~= "" then + -- Relative filename - construct full path from install_path + icon_path = app.install_path .. "/" .. app.icon + else + icon_path = app.icon + end + -- Use img tag for actual icon + icon_html = '' + print("[Home] Loading icon: " .. icon_path) else + -- Fallback to initial letter icon_html = '' .. initial .. '' end @@ -151,9 +163,16 @@ function launchThirdPartyApp(package_id) if success then print("[Home] App sandbox started: " .. package_id) - -- Now load the app's UI document + -- Get app info for sandbox switching and UI loading local app_info = getAppInfo(package_id) if app_info and app_info.install_path and app_info.entry_point then + -- Switch sandbox context to this app (registers timer, fs, json, crypto APIs) + if switchAppSandbox then + switchAppSandbox(package_id, app_info.install_path) + print("[Home] Sandbox context switched to: " .. package_id) + end + + -- Now load the app's UI document local entry_path = app_info.install_path .. "/" .. app_info.entry_point print("[Home] Loading app screen: " .. entry_path) local loaded = loadScreen(entry_path) diff --git a/src/main/cpp/kernel.cpp b/src/main/cpp/kernel.cpp index cfb5d87..678b446 100644 --- a/src/main/cpp/kernel.cpp +++ b/src/main/cpp/kernel.cpp @@ -21,6 +21,12 @@ #include #include +// Sandbox API includes for RmlUi integration +#include +#include +#include +#include + // Global state for Lua access static Rml::Context* g_context = nullptr; static Rml::ElementDocument* g_document = nullptr; @@ -28,6 +34,15 @@ static mosis::AppManager* g_app_manager = nullptr; static mosis::UpdateService* g_update_service = nullptr; static mosis::LuaSandboxManager* g_sandbox_manager = nullptr; +// RmlUi sandbox state - APIs registered into RmlUi's Lua state +static std::unique_ptr g_rmlui_timer_manager; +static std::unique_ptr g_rmlui_vfs; +static std::string g_current_app_id = "com.mosis.home"; +static std::string g_data_root; + +// Forward declarations +static void SwitchAppSandbox(const std::string& app_id, const std::string& app_data_path); + using namespace aidl::com::omixlab::mosis; using namespace aidl::android::hardware; @@ -268,7 +283,7 @@ static int LuaGoHome(lua_State* L) Logger::Log("goHome called - returning to home screen"); - // Stop any running third-party app + // Stop any running third-party app in the legacy sandbox manager if (g_sandbox_manager) { auto running_apps = g_sandbox_manager->GetRunningApps(); for (const auto& app_id : running_apps) { @@ -280,6 +295,9 @@ static int LuaGoHome(lua_State* L) } } + // Switch sandbox context back to home screen + SwitchAppSandbox("com.mosis.home", g_data_root); + // Load home screen const char* home_path = "apps/home/home.rml"; @@ -307,6 +325,113 @@ static int LuaGoHome(lua_State* L) return 1; } +// Register sandbox APIs (timer, json, crypto, fs) into RmlUi's Lua state +static void RegisterSandboxAPIs(lua_State* L) +{ + Logger::Log("Registering sandbox APIs..."); + + // Register timer API + if (g_rmlui_timer_manager) { + mosis::RegisterTimerAPI(L, g_rmlui_timer_manager.get(), g_current_app_id); + Logger::Log(" Timer API registered"); + } + + // Register JSON API + mosis::RegisterJsonAPI(L, mosis::JsonLimits{}); + Logger::Log(" JSON API registered"); + + // Register crypto API + mosis::RegisterCryptoAPI(L); + Logger::Log(" Crypto API registered"); + + // Register virtual filesystem API + if (g_rmlui_vfs) { + mosis::RegisterVirtualFS(L, g_rmlui_vfs.get()); + Logger::Log(" VirtualFS API registered"); + } + + Logger::Log("All sandbox APIs registered"); +} + +// Unregister sandbox APIs (for clean switch between apps) +static void UnregisterSandboxAPIs(lua_State* L) +{ + // Clear timer globals + lua_pushnil(L); + lua_setglobal(L, "setTimeout"); + lua_pushnil(L); + lua_setglobal(L, "clearTimeout"); + lua_pushnil(L); + lua_setglobal(L, "setInterval"); + lua_pushnil(L); + lua_setglobal(L, "clearInterval"); + + // Clear json global + lua_pushnil(L); + lua_setglobal(L, "json"); + + // Clear crypto global + lua_pushnil(L); + lua_setglobal(L, "crypto"); + + // Clear fs global + lua_pushnil(L); + lua_setglobal(L, "fs"); + + Logger::Log("Sandbox APIs unregistered"); +} + +// Switch sandbox context to a different app +static void SwitchAppSandbox(const std::string& app_id, const std::string& app_data_path) +{ + lua_State* L = Rml::Lua::Interpreter::GetLuaState(); + + // Clear timers for current app + if (g_rmlui_timer_manager) { + g_rmlui_timer_manager->ClearAppTimers(g_current_app_id); + Logger::Log(std::format("Timers cleared for {}", g_current_app_id)); + } + + // Unregister current APIs + UnregisterSandboxAPIs(L); + + // Update current app ID + g_current_app_id = app_id; + + // Create new VirtualFS for the app + std::string vfs_path = app_data_path.empty() ? + (g_data_root + "/sandbox_data") : + (app_data_path + "/sandbox_data"); + + std::filesystem::create_directories(vfs_path); + + g_rmlui_vfs = std::make_unique( + app_id, + vfs_path, + mosis::VirtualFSLimits{} + ); + + Logger::Log(std::format("VirtualFS created for {} at {}", app_id, vfs_path)); + + // Register APIs for new app + RegisterSandboxAPIs(L); +} + +// Lua function to switch sandbox context for a third-party app +// Called before loading an app's UI: switchAppSandbox(app_id, install_path) +static int LuaSwitchAppSandbox(lua_State* L) +{ + const char* app_id = luaL_checkstring(L, 1); + const char* install_path = luaL_checkstring(L, 2); + + Logger::Log(std::format("Switching sandbox to app: {} at {}", app_id, install_path)); + + SwitchAppSandbox(app_id, install_path); + + lua_pushboolean(L, true); + return 1; +} + // Register Lua functions for navigation static void RegisterLuaFunctions(const std::string& current_app_id, bool is_system_app) { @@ -315,13 +440,18 @@ static void RegisterLuaFunctions(const std::string& current_app_id, bool is_syst lua_setglobal(L, "loadScreen"); lua_pushcfunction(L, LuaGoHome); lua_setglobal(L, "goHome"); - Logger::Log("Registered Lua loadScreen and goHome functions"); + lua_pushcfunction(L, LuaSwitchAppSandbox); + lua_setglobal(L, "switchAppSandbox"); + Logger::Log("Registered Lua loadScreen, goHome, and switchAppSandbox functions"); // Register app management APIs if (g_app_manager && g_update_service) { mosis::RegisterAppAPIs(L, g_app_manager, g_update_service, current_app_id, is_system_app); Logger::Log("Registered Lua app management APIs"); } + + // Initialize and register sandbox APIs + RegisterSandboxAPIs(L); } void Kernel::main_loop() @@ -362,6 +492,7 @@ void Kernel::main_loop() // Initialize app management system // TODO: Get data root from Android context (for now use a placeholder) std::string data_root = "/data/data/com.omixlab.mosis/files"; + g_data_root = data_root; // Store for sandbox switching m_app_manager = std::make_unique(data_root); m_update_service = std::make_unique( m_app_manager.get(), "https://portal.mosis.dev/api/v1"); @@ -372,6 +503,14 @@ void Kernel::main_loop() g_sandbox_manager = m_sandbox_manager.get(); Logger::Log("App management system initialized"); + // Initialize RmlUi sandbox state (timer manager and VFS for home screen) + g_rmlui_timer_manager = std::make_unique(); + std::string home_sandbox_path = data_root + "/sandbox_data"; + std::filesystem::create_directories(home_sandbox_path); + g_rmlui_vfs = std::make_unique( + "com.mosis.home", home_sandbox_path, mosis::VirtualFSLimits{}); + Logger::Log("RmlUi sandbox initialized"); + // Start background update checks (every 24 hours) m_update_service->Start(std::chrono::hours(24)); @@ -415,11 +554,16 @@ void Kernel::main_loop() m_tasks.clear(); } - // Update sandbox timers for running apps + // Update sandbox timers for running apps (legacy sandbox manager) if (m_sandbox_manager) { m_sandbox_manager->UpdateTimers(); } + // Update RmlUi sandbox timers (for UI-based apps) + if (g_rmlui_timer_manager) { + g_rmlui_timer_manager->ProcessTimers(); + } + m_render_target->bind(); glClearColor(0.f, 0.f, 0.f, 1.f); glClear(GL_COLOR_BUFFER_BIT);