From d6b75044086a95ea03b3e6d092dd5aaa6f5fcf99 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Mon, 19 Jan 2026 13:50:05 +0100 Subject: [PATCH] implement third-party app launching from home screen --- src/main/assets/apps/home/home.lua | 27 +++- src/main/cpp/apps/app_api.cpp | 6 + src/main/cpp/apps/app_manager.cpp | 18 ++- src/main/cpp/kernel.cpp | 193 ++++++++++++++++++++++++----- src/main/cpp/kernel.h | 3 +- 5 files changed, 214 insertions(+), 33 deletions(-) diff --git a/src/main/assets/apps/home/home.lua b/src/main/assets/apps/home/home.lua index dca426b..176f8ae 100644 --- a/src/main/assets/apps/home/home.lua +++ b/src/main/assets/apps/home/home.lua @@ -132,6 +132,16 @@ function renderThirdPartyApps() print("[Home] Rendered " .. #installed_apps .. " third-party apps") end +-- Get app info by package_id +function getAppInfo(package_id) + for _, app in ipairs(installed_apps) do + if app.package_id == package_id then + return app + end + end + return nil +end + -- Launch a third-party app function launchThirdPartyApp(package_id) print("[Home] Launching app: " .. package_id) @@ -139,7 +149,22 @@ function launchThirdPartyApp(package_id) if mosis and mosis.apps then local success = mosis.apps.launch(package_id) if success then - print("[Home] App launched: " .. package_id) + print("[Home] App sandbox started: " .. package_id) + + -- Now load the app's UI document + local app_info = getAppInfo(package_id) + if app_info and app_info.install_path and app_info.entry_point then + local entry_path = app_info.install_path .. "/" .. app_info.entry_point + print("[Home] Loading app screen: " .. entry_path) + local loaded = loadScreen(entry_path) + if loaded then + print("[Home] App UI loaded: " .. package_id) + else + print("[Home] Failed to load app UI: " .. entry_path) + end + else + print("[Home] App info missing entry point: " .. package_id) + end else print("[Home] Failed to launch app: " .. package_id) end diff --git a/src/main/cpp/apps/app_api.cpp b/src/main/cpp/apps/app_api.cpp index 0f3f320..1ed1792 100644 --- a/src/main/cpp/apps/app_api.cpp +++ b/src/main/cpp/apps/app_api.cpp @@ -95,6 +95,12 @@ static int apps_getInstalled(lua_State* L) { lua_pushstring(L, app.developer_name.c_str()); lua_setfield(L, -2, "developer"); + lua_pushstring(L, app.install_path.c_str()); + lua_setfield(L, -2, "install_path"); + + lua_pushstring(L, app.entry_point.c_str()); + lua_setfield(L, -2, "entry_point"); + // installed_at as Unix timestamp auto ts = std::chrono::duration_cast( app.installed_at.time_since_epoch()).count(); diff --git a/src/main/cpp/apps/app_manager.cpp b/src/main/cpp/apps/app_manager.cpp index deaf25e..b89b68d 100644 --- a/src/main/cpp/apps/app_manager.cpp +++ b/src/main/cpp/apps/app_manager.cpp @@ -330,7 +330,23 @@ bool AppManager::LaunchApp(const std::string& package_id) { return true; } - std::string app_path = app->install_path + "/package"; + // Determine app path - check for package/ subfolder or direct structure + std::string app_path; + std::string package_subdir = app->install_path + "/package"; + std::string entry_in_package = package_subdir + "/" + app->entry_point; + std::string entry_direct = app->install_path + "/" + app->entry_point; + + if (fs::exists(entry_in_package)) { + // Installed package structure: files in package/ subfolder + app_path = package_subdir; + } else if (fs::exists(entry_direct)) { + // Direct structure: files in install_path directly + app_path = app->install_path; + } else { + LOG_ERROR("Cannot launch app: entry point not found: %s", app->entry_point.c_str()); + return false; + } + LOG_INFO("Launching app: %s from %s", package_id.c_str(), app_path.c_str()); return m_sandbox_manager->StartApp(package_id, app_path, app->permissions, app->is_system_app); diff --git a/src/main/cpp/kernel.cpp b/src/main/cpp/kernel.cpp index 8ff87cd..62ac050 100644 --- a/src/main/cpp/kernel.cpp +++ b/src/main/cpp/kernel.cpp @@ -6,6 +6,7 @@ #include "apps/app_manager.h" #include "apps/update_service.h" #include "apps/app_api.h" +#include "sandbox/sandbox_manager.h" #include "aidl/com/omixlab/mosis/IMosisListener.h" #include #include @@ -17,16 +18,30 @@ #include #include #include +#include +#include // Global state for Lua access static Rml::Context* g_context = nullptr; static Rml::ElementDocument* g_document = nullptr; static mosis::AppManager* g_app_manager = nullptr; static mosis::UpdateService* g_update_service = nullptr; +static mosis::LuaSandboxManager* g_sandbox_manager = nullptr; using namespace aidl::com::omixlab::mosis; using namespace aidl::android::hardware; +// File handle wrapper to support both assets and filesystem files +struct FileHandleWrapper { + enum class Type { Asset, File }; + Type type; + union { + AAsset* asset; + std::ifstream* file; + }; + size_t file_size = 0; // For filesystem files +}; + class AssetFilesInterface : public Rml::FileInterface { public: @@ -35,51 +50,137 @@ public: static AssetFilesInterface instance; return instance; } + + // Check if path is a filesystem path (starts with /) + static bool IsFilesystemPath(const Rml::String& path) { + return !path.empty() && path[0] == '/'; + } + Rml::FileHandle Open(const Rml::String &path) override { - AAssetManager* am = AssetsManager::Native(); - AAsset* asset = AAssetManager_open(am, path.c_str(), AASSET_MODE_BUFFER); - return reinterpret_cast(asset); + auto* wrapper = new FileHandleWrapper(); + + if (IsFilesystemPath(path)) { + // Filesystem path + auto* file = new std::ifstream(path, std::ios::binary); + if (!file->is_open()) { + delete file; + delete wrapper; + return 0; + } + file->seekg(0, std::ios::end); + wrapper->file_size = file->tellg(); + file->seekg(0, std::ios::beg); + wrapper->type = FileHandleWrapper::Type::File; + wrapper->file = file; + } else { + // Asset path + AAssetManager* am = AssetsManager::Native(); + AAsset* asset = AAssetManager_open(am, path.c_str(), AASSET_MODE_BUFFER); + if (!asset) { + delete wrapper; + return 0; + } + wrapper->type = FileHandleWrapper::Type::Asset; + wrapper->asset = asset; + } + + return reinterpret_cast(wrapper); } + void Close(Rml::FileHandle file) override { - AAsset* asset = reinterpret_cast(file); - AAsset_close(asset); + auto* wrapper = reinterpret_cast(file); + if (!wrapper) return; + + if (wrapper->type == FileHandleWrapper::Type::Asset) { + AAsset_close(wrapper->asset); + } else { + wrapper->file->close(); + delete wrapper->file; + } + delete wrapper; } + size_t Read(void *buffer, size_t size, Rml::FileHandle file) override { - AAsset* asset = reinterpret_cast(file); - return AAsset_read(asset, buffer, size); + auto* wrapper = reinterpret_cast(file); + if (!wrapper) return 0; + + if (wrapper->type == FileHandleWrapper::Type::Asset) { + return AAsset_read(wrapper->asset, buffer, size); + } else { + wrapper->file->read(static_cast(buffer), size); + return wrapper->file->gcount(); + } } + bool Seek(Rml::FileHandle file, long offset, int origin) override { - AAsset* asset = reinterpret_cast(file); - off_t new_cursor = AAsset_seek(asset, offset, origin); - return new_cursor != -1; + auto* wrapper = reinterpret_cast(file); + if (!wrapper) return false; + + if (wrapper->type == FileHandleWrapper::Type::Asset) { + off_t new_cursor = AAsset_seek(wrapper->asset, offset, origin); + return new_cursor != -1; + } else { + std::ios_base::seekdir dir = std::ios::beg; + if (origin == SEEK_CUR) dir = std::ios::cur; + else if (origin == SEEK_END) dir = std::ios::end; + wrapper->file->seekg(offset, dir); + return !wrapper->file->fail(); + } } + size_t Tell(Rml::FileHandle file) override { - AAsset* asset = reinterpret_cast(file); - return AAsset_seek(asset, 0, SEEK_CUR); + auto* wrapper = reinterpret_cast(file); + if (!wrapper) return 0; + + if (wrapper->type == FileHandleWrapper::Type::Asset) { + return AAsset_seek(wrapper->asset, 0, SEEK_CUR); + } else { + return wrapper->file->tellg(); + } } size_t Length(Rml::FileHandle file) override { - AAsset* asset = reinterpret_cast(file); - return AAsset_getLength(asset); + auto* wrapper = reinterpret_cast(file); + if (!wrapper) return 0; + + if (wrapper->type == FileHandleWrapper::Type::Asset) { + return AAsset_getLength(wrapper->asset); + } else { + return wrapper->file_size; + } } bool LoadFile(const Rml::String &path, Rml::String &out_data) override { - AAssetManager* am = AssetsManager::Native(); - AAsset* asset = AAssetManager_open(am, path.c_str(), AASSET_MODE_BUFFER); - if (!asset) - return false; - out_data.resize(AAsset_getLength(asset)); - auto data_ptr = static_cast(AAsset_getBuffer(asset)); - std::span data = std::span(data_ptr, out_data.size()); - std::ranges::copy(data, out_data.begin()); - return true; + if (IsFilesystemPath(path)) { + // Load from filesystem + std::ifstream file(path, std::ios::binary | std::ios::ate); + if (!file.is_open()) return false; + + size_t size = file.tellg(); + file.seekg(0, std::ios::beg); + out_data.resize(size); + file.read(out_data.data(), size); + return true; + } else { + // Load from assets + AAssetManager* am = AssetsManager::Native(); + AAsset* asset = AAssetManager_open(am, path.c_str(), AASSET_MODE_BUFFER); + if (!asset) return false; + + out_data.resize(AAsset_getLength(asset)); + auto data_ptr = static_cast(AAsset_getBuffer(asset)); + std::span data = std::span(data_ptr, out_data.size()); + std::ranges::copy(data, out_data.begin()); + AAsset_close(asset); + return true; + } } }; @@ -110,16 +211,27 @@ static int LuaLoadScreen(lua_State* L) const char* path = luaL_checkstring(L, 1); Logger::Log(std::format("Loading screen: {}", path)); - // Check if asset exists - AAssetManager* am = AssetsManager::Native(); - AAsset* asset = AAssetManager_open(am, path, AASSET_MODE_BUFFER); - if (!asset) + // Check if file exists - support both asset and filesystem paths + bool exists = false; + if (AssetFilesInterface::IsFilesystemPath(path)) { + // Filesystem path + exists = std::filesystem::exists(path); + } else { + // Asset path + AAssetManager* am = AssetsManager::Native(); + AAsset* asset = AAssetManager_open(am, path, AASSET_MODE_BUFFER); + if (asset) { + exists = true; + AAsset_close(asset); + } + } + + if (!exists) { Logger::Log(std::format("Screen not found: {}", path)); lua_pushboolean(L, false); return 1; } - AAsset_close(asset); // Unload current document if (g_document) @@ -201,8 +313,11 @@ void Kernel::main_loop() m_app_manager = std::make_unique(data_root); m_update_service = std::make_unique( m_app_manager.get(), "https://portal.mosis.dev/api/v1"); + m_sandbox_manager = std::make_unique(data_root); + m_app_manager->SetSandboxManager(m_sandbox_manager.get()); g_app_manager = m_app_manager.get(); g_update_service = m_update_service.get(); + g_sandbox_manager = m_sandbox_manager.get(); Logger::Log("App management system initialized"); // Start background update checks (every 24 hours) @@ -248,6 +363,11 @@ void Kernel::main_loop() m_tasks.clear(); } + // Update sandbox timers for running apps + if (m_sandbox_manager) { + m_sandbox_manager->UpdateTimers(); + } + m_render_target->bind(); glClearColor(0.f, 0.f, 0.f, 1.f); glClear(GL_COLOR_BUFFER_BIT); @@ -289,8 +409,21 @@ void Kernel::on_touch_down(float x, float y) Logger::Log(std::format("on_touch_down {} - {}", x, y)); std::lock_guard _lock(m_mutex); m_tasks.emplace_back([x, y](Rml::Context* context){ - context->ProcessMouseMove(static_cast(x * 540), static_cast(y * 960), 0); - context->ProcessMouseButtonDown(0, 0); + int px = static_cast(x * 540); + int py = static_cast(y * 960); + bool move_handled = context->ProcessMouseMove(px, py, 0); + bool down_handled = context->ProcessMouseButtonDown(0, 0); + Logger::Log(std::format("Touch at ({}, {}): move={}, down={}", px, py, move_handled, down_handled)); + + // Debug: Check if there's a hover element + auto* hover_elem = context->GetHoverElement(); + if (hover_elem) { + Logger::Log(std::format(" Hover element: {} (id={})", + hover_elem->GetTagName().c_str(), + hover_elem->GetId().c_str())); + } else { + Logger::Log(" No hover element at this position"); + } }); } diff --git a/src/main/cpp/kernel.h b/src/main/cpp/kernel.h index 3869481..41cce92 100644 --- a/src/main/cpp/kernel.h +++ b/src/main/cpp/kernel.h @@ -11,7 +11,7 @@ namespace egl { class Context; } namespace aidl::com::omixlab::mosis { class IMosisListener; } namespace aidl::android::hardware { struct HardwareBuffer; } namespace Rml { class Context; } -namespace mosis { class AppManager; class UpdateService; } +namespace mosis { class AppManager; class UpdateService; class LuaSandboxManager; } class Kernel { @@ -21,6 +21,7 @@ class Kernel std::unique_ptr m_aidl_buffer; std::unique_ptr m_app_manager; std::unique_ptr m_update_service; + std::unique_ptr m_sandbox_manager; std::vector> m_tasks; std::mutex m_mutex; std::thread m_main_loop_thread;