Add sandbox API integration for RmlUi Lua state
- Register sandbox APIs (timer, JSON, crypto, VFS) into RmlUi's Lua state - Add switchAppSandbox() function for context switching between apps - Update goHome() to reset sandbox context when returning home - Fix icon loading for third-party apps (handle full paths vs relative) - Mirror changes between Android service (kernel.cpp) and desktop designer This enables third-party apps to use sandbox APIs when running in RmlUi. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -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<mosis::DesktopSandbox>(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<mosis::DesktopSandbox>(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) {
|
||||
|
||||
@@ -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 = '<span style="font-size: 28px; color: #000000;">' .. initial .. '</span>'
|
||||
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 = '<img src="' .. icon_path .. '" style="width: 48px; height: 48px;"/>'
|
||||
print("[Home] Loading icon: " .. icon_path)
|
||||
else
|
||||
-- Fallback to initial letter
|
||||
icon_html = '<span style="font-size: 28px; color: #000000;">' .. initial .. '</span>'
|
||||
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)
|
||||
|
||||
@@ -21,6 +21,12 @@
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
|
||||
// Sandbox API includes for RmlUi integration
|
||||
#include <mosis/sandbox/timer_manager.h>
|
||||
#include <mosis/sandbox/json_api.h>
|
||||
#include <mosis/sandbox/crypto_api.h>
|
||||
#include <mosis/sandbox/virtual_fs.h>
|
||||
|
||||
// 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<mosis::TimerManager> g_rmlui_timer_manager;
|
||||
static std::unique_ptr<mosis::VirtualFS> 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<mosis::VirtualFS>(
|
||||
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<mosis::AppManager>(data_root);
|
||||
m_update_service = std::make_unique<mosis::UpdateService>(
|
||||
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<mosis::TimerManager>();
|
||||
std::string home_sandbox_path = data_root + "/sandbox_data";
|
||||
std::filesystem::create_directories(home_sandbox_path);
|
||||
g_rmlui_vfs = std::make_unique<mosis::VirtualFS>(
|
||||
"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);
|
||||
|
||||
Reference in New Issue
Block a user