diff --git a/install-device.bat b/install-device.bat new file mode 100644 index 0000000..08bdfc1 --- /dev/null +++ b/install-device.bat @@ -0,0 +1,70 @@ +@echo off +setlocal enabledelayedexpansion + +echo ======================================== +echo Mosis Device Installation Script +echo ======================================== +echo. + +:: Package name +set PACKAGE=com.omixlab.mosis +set DEVICE_APPS_DIR=files/apps + +:: Step 1: Build and install APK +echo [1/3] Building and installing debug APK... +call gradlew installDebug +if errorlevel 1 ( + echo ERROR: Failed to install APK + exit /b 1 +) +echo. + +:: Step 2: Push base-apps to temp location +echo [2/3] Pushing base-apps to temp location... +adb shell "rm -rf /data/local/tmp/mosis-apps" 2>nul +adb push base-apps /data/local/tmp/mosis-apps +if errorlevel 1 ( + echo ERROR: Failed to push base-apps + exit /b 1 +) +echo. + +:: Step 3: Copy to private data using run-as +echo [3/3] Installing apps to internal storage... +echo Using run-as for /data/data/%PACKAGE%/%DEVICE_APPS_DIR%/ +echo. + +:: Create apps directory +adb shell "run-as %PACKAGE% mkdir -p %DEVICE_APPS_DIR%" + +:: List of apps to install +for /d %%A in (base-apps\com.mosis.*) do ( + set APP_ID=%%~nxA + echo Installing !APP_ID!... + + :: Create app directory structure + adb shell "run-as %PACKAGE% mkdir -p %DEVICE_APPS_DIR%/!APP_ID!" + + :: Copy files using tar through run-as (faster than individual files) + adb shell "cd /data/local/tmp/mosis-apps/!APP_ID! && tar cf - . | run-as %PACKAGE% tar xf - -C %DEVICE_APPS_DIR%/!APP_ID!/" +) + +:: Cleanup temp files +echo. +echo Cleaning up temp files... +adb shell "rm -rf /data/local/tmp/mosis-apps" + +echo. +echo ======================================== +echo Installation complete! +echo ======================================== +echo. +echo APK: %PACKAGE% +echo Apps: /data/data/%PACKAGE%/%DEVICE_APPS_DIR%/ +echo. +echo Verify with: +echo adb shell "run-as %PACKAGE% ls -la %DEVICE_APPS_DIR%" +echo. +echo Launch with: +echo adb shell am start -n %PACKAGE%/.MainActivity +echo. diff --git a/src/main/assets/apps/shell/shell.lua b/src/main/assets/apps/shell/shell.lua index d36ceeb..fc07def 100644 --- a/src/main/assets/apps/shell/shell.lua +++ b/src/main/assets/apps/shell/shell.lua @@ -385,17 +385,31 @@ function getAppColor(package_id) return color end +-- Built-in system apps (fallback when mosis.apps not available or empty) +local builtin_apps = { + {package_id = "com.mosis.browser", name = "Browser", icon = "../../icons/browser.tga"}, + {package_id = "com.mosis.camera", name = "Camera", icon = "../../icons/camera.tga"}, + {package_id = "com.mosis.contacts", name = "Contacts", icon = "../../icons/contacts.tga"}, + {package_id = "com.mosis.dialer", name = "Phone", icon = "../../icons/phone.tga"}, + {package_id = "com.mosis.messages", name = "Messages", icon = "../../icons/message.tga"}, + {package_id = "com.mosis.music", name = "Music", icon = "../../icons/music.tga"}, + {package_id = "com.mosis.settings", name = "Settings", icon = "../../icons/settings.tga"}, + {package_id = "com.mosis.store", name = "Store", icon = "../../icons/store.tga"}, +} + -- Populate home screen with discovered apps function populateHomeApps() - if not mosis or not mosis.apps then - print("[Shell] mosis.apps not available") - return + local apps = nil + + -- Try to get installed apps from mosis.apps API + if mosis and mosis.apps then + apps = mosis.apps.getInstalled() end - local apps = mosis.apps.getInstalled() + -- Fall back to built-in apps if none discovered if not apps or #apps == 0 then - print("[Shell] No apps discovered") - return + print("[Shell] Using built-in system apps") + apps = builtin_apps end print("[Shell] Populating home with " .. #apps .. " apps") @@ -468,37 +482,48 @@ end -- Launch a discovered app by package_id function launchDiscoveredApp(package_id) - if not mosis or not mosis.apps then - print("[Shell] mosis.apps not available") - showToast("Cannot launch app", "error") - return + print("[Shell] Launching app: " .. package_id) + + -- Check if it's a built-in system app + local app_id = package_id:gsub("com.mosis.", "") + local builtin_ids = { + browser = true, camera = true, contacts = true, dialer = true, + messages = true, music = true, settings = true, store = true + } + + if builtin_ids[app_id] then + -- Use shellNavigateTo for built-in apps + return shellNavigateTo(app_id) end - local apps = mosis.apps.getInstalled() - for _, app in ipairs(apps) do - if app.package_id == package_id then - print("[Shell] Launching discovered app: " .. package_id) + -- Try to find in installed apps + if mosis and mosis.apps then + local apps = mosis.apps.getInstalled() + for _, app in ipairs(apps) do + if app.package_id == package_id then + print("[Shell] Launching installed app: " .. package_id) - -- Push current to history - if current_app then - table.insert(nav_history, { - app_id = current_app, - app_path = current_app_path - }) - print("[Shell] Pushed to history: " .. current_app .. " (depth: " .. #nav_history .. ")") + -- Push current to history + if current_app then + table.insert(nav_history, { + app_id = current_app, + app_path = current_app_path + }) + print("[Shell] Pushed to history: " .. current_app .. " (depth: " .. #nav_history .. ")") + end + + -- Build content path - convert entry.rml to entry_content.rml + local entry = app.entry_point or "main.rml" + local content_entry = entry:gsub("%.rml$", "_content.rml") + local content_path = "apps/" .. package_id:gsub("com.mosis.", "") .. "/" .. content_entry + + -- Switch sandbox if available + if switchAppSandbox then + switchAppSandbox(package_id, app.install_path) + end + + return loadAppContent_internal(package_id, content_path) end - - -- Build content path - convert entry.rml to entry_content.rml - local entry = app.entry_point or "main.rml" - local content_entry = entry:gsub("%.rml$", "_content.rml") - local content_path = "apps/" .. package_id:gsub("com.mosis.", "") .. "/" .. content_entry - - -- Switch sandbox if available - if switchAppSandbox then - switchAppSandbox(package_id, app.install_path) - end - - return loadAppContent_internal(package_id, content_path) end end diff --git a/src/main/cpp/kernel.cpp b/src/main/cpp/kernel.cpp index 94b1456..379b313 100644 --- a/src/main/cpp/kernel.cpp +++ b/src/main/cpp/kernel.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include // Sandbox API includes for RmlUi integration @@ -390,8 +391,8 @@ 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"; + // Load shell (which shows home by default) + const char* home_path = "apps/shell/shell.rml"; // Unload current document if (g_document) @@ -525,6 +526,57 @@ static int LuaSwitchAppSandbox(lua_State* L) return 1; } +// Load app content fragment into a container element +static int LuaLoadAppContent(lua_State* L) +{ + // Get element from first argument + Rml::Element* element = Rml::Lua::LuaType::check(L, 1); + if (!element) { + Logger::Log("loadAppContent: Invalid element argument"); + lua_pushboolean(L, false); + return 1; + } + + // Get path from second argument + const char* path = luaL_checkstring(L, 2); + Logger::Log(std::format("loadAppContent: Loading {} into element", path)); + + // Read file content - try assets first, then filesystem + std::string content; + AAssetManager* am = AssetsManager::Native(); + AAsset* asset = AAssetManager_open(am, path, AASSET_MODE_BUFFER); + + if (asset) { + // Load from assets + size_t length = AAsset_getLength(asset); + const char* data = static_cast(AAsset_getBuffer(asset)); + content = std::string(data, length); + AAsset_close(asset); + Logger::Log(std::format(" -> Loaded {} bytes from assets", length)); + } else { + // Try filesystem (for installed apps) + std::string fs_path = GetFilesDir() + "/" + path; + std::ifstream file(fs_path); + if (file.is_open()) { + std::stringstream buffer; + buffer << file.rdbuf(); + content = buffer.str(); + Logger::Log(std::format(" -> Loaded {} bytes from filesystem", content.size())); + } else { + Logger::Log(std::format("loadAppContent: Cannot open file: {}", path)); + lua_pushboolean(L, false); + return 1; + } + } + + // Set inner RML + element->SetInnerRML(content); + Logger::Log("loadAppContent: Content loaded successfully"); + + lua_pushboolean(L, true); + return 1; +} + // Register Lua functions for navigation static void RegisterLuaFunctions(const std::string& current_app_id, bool is_system_app) { @@ -535,7 +587,9 @@ static void RegisterLuaFunctions(const std::string& current_app_id, bool is_syst lua_setglobal(L, "goHome"); lua_pushcfunction(L, LuaSwitchAppSandbox); lua_setglobal(L, "switchAppSandbox"); - Logger::Log("Registered Lua loadScreen, goHome, and switchAppSandbox functions"); + lua_pushcfunction(L, LuaLoadAppContent); + lua_setglobal(L, "loadAppContent"); + Logger::Log("Registered Lua loadScreen, goHome, switchAppSandbox, and loadAppContent functions"); // Register app management APIs if (g_app_manager && g_update_service) { @@ -633,11 +687,11 @@ void Kernel::main_loop() Rml::LoadFontFace("fonts/Roboto/Roboto-VariableFont_wdth,wght.ttf"); Rml::LoadFontFace("fonts/Roboto/Roboto-Italic-VariableFont_wdth,wght.ttf"); - // Load home screen document - g_document = g_context->LoadDocument("apps/home/home.rml"); + // Load shell document (provides persistent status bar, nav bar, and loads home content) + g_document = g_context->LoadDocument("apps/shell/shell.rml"); if (!g_document) { - Logger::Log("Failed to load home.rml document"); + Logger::Log("Failed to load shell.rml document"); Rml::Shutdown(); return; }