fix Android: load shell.rml, add loadAppContent function, fallback to built-in apps
This commit is contained in:
70
install-device.bat
Normal file
70
install-device.bat
Normal file
@@ -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.
|
||||||
@@ -385,17 +385,31 @@ function getAppColor(package_id)
|
|||||||
return color
|
return color
|
||||||
end
|
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
|
-- Populate home screen with discovered apps
|
||||||
function populateHomeApps()
|
function populateHomeApps()
|
||||||
if not mosis or not mosis.apps then
|
local apps = nil
|
||||||
print("[Shell] mosis.apps not available")
|
|
||||||
return
|
-- Try to get installed apps from mosis.apps API
|
||||||
|
if mosis and mosis.apps then
|
||||||
|
apps = mosis.apps.getInstalled()
|
||||||
end
|
end
|
||||||
|
|
||||||
local apps = mosis.apps.getInstalled()
|
-- Fall back to built-in apps if none discovered
|
||||||
if not apps or #apps == 0 then
|
if not apps or #apps == 0 then
|
||||||
print("[Shell] No apps discovered")
|
print("[Shell] Using built-in system apps")
|
||||||
return
|
apps = builtin_apps
|
||||||
end
|
end
|
||||||
|
|
||||||
print("[Shell] Populating home with " .. #apps .. " apps")
|
print("[Shell] Populating home with " .. #apps .. " apps")
|
||||||
@@ -468,37 +482,48 @@ end
|
|||||||
|
|
||||||
-- Launch a discovered app by package_id
|
-- Launch a discovered app by package_id
|
||||||
function launchDiscoveredApp(package_id)
|
function launchDiscoveredApp(package_id)
|
||||||
if not mosis or not mosis.apps then
|
print("[Shell] Launching app: " .. package_id)
|
||||||
print("[Shell] mosis.apps not available")
|
|
||||||
showToast("Cannot launch app", "error")
|
-- Check if it's a built-in system app
|
||||||
return
|
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
|
end
|
||||||
|
|
||||||
local apps = mosis.apps.getInstalled()
|
-- Try to find in installed apps
|
||||||
for _, app in ipairs(apps) do
|
if mosis and mosis.apps then
|
||||||
if app.package_id == package_id then
|
local apps = mosis.apps.getInstalled()
|
||||||
print("[Shell] Launching discovered app: " .. package_id)
|
for _, app in ipairs(apps) do
|
||||||
|
if app.package_id == package_id then
|
||||||
|
print("[Shell] Launching installed app: " .. package_id)
|
||||||
|
|
||||||
-- Push current to history
|
-- Push current to history
|
||||||
if current_app then
|
if current_app then
|
||||||
table.insert(nav_history, {
|
table.insert(nav_history, {
|
||||||
app_id = current_app,
|
app_id = current_app,
|
||||||
app_path = current_app_path
|
app_path = current_app_path
|
||||||
})
|
})
|
||||||
print("[Shell] Pushed to history: " .. current_app .. " (depth: " .. #nav_history .. ")")
|
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
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
// Sandbox API includes for RmlUi integration
|
// Sandbox API includes for RmlUi integration
|
||||||
@@ -390,8 +391,8 @@ static int LuaGoHome(lua_State* L)
|
|||||||
// Switch sandbox context back to home screen
|
// Switch sandbox context back to home screen
|
||||||
SwitchAppSandbox("com.mosis.home", g_data_root);
|
SwitchAppSandbox("com.mosis.home", g_data_root);
|
||||||
|
|
||||||
// Load home screen
|
// Load shell (which shows home by default)
|
||||||
const char* home_path = "apps/home/home.rml";
|
const char* home_path = "apps/shell/shell.rml";
|
||||||
|
|
||||||
// Unload current document
|
// Unload current document
|
||||||
if (g_document)
|
if (g_document)
|
||||||
@@ -525,6 +526,57 @@ static int LuaSwitchAppSandbox(lua_State* L)
|
|||||||
return 1;
|
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<Rml::Element>::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<const char*>(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
|
// Register Lua functions for navigation
|
||||||
static void RegisterLuaFunctions(const std::string& current_app_id, bool is_system_app)
|
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_setglobal(L, "goHome");
|
||||||
lua_pushcfunction(L, LuaSwitchAppSandbox);
|
lua_pushcfunction(L, LuaSwitchAppSandbox);
|
||||||
lua_setglobal(L, "switchAppSandbox");
|
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
|
// Register app management APIs
|
||||||
if (g_app_manager && g_update_service) {
|
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-VariableFont_wdth,wght.ttf");
|
||||||
Rml::LoadFontFace("fonts/Roboto/Roboto-Italic-VariableFont_wdth,wght.ttf");
|
Rml::LoadFontFace("fonts/Roboto/Roboto-Italic-VariableFont_wdth,wght.ttf");
|
||||||
|
|
||||||
// Load home screen document
|
// Load shell document (provides persistent status bar, nav bar, and loads home content)
|
||||||
g_document = g_context->LoadDocument("apps/home/home.rml");
|
g_document = g_context->LoadDocument("apps/shell/shell.rml");
|
||||||
if (!g_document)
|
if (!g_document)
|
||||||
{
|
{
|
||||||
Logger::Log("Failed to load home.rml document");
|
Logger::Log("Failed to load shell.rml document");
|
||||||
Rml::Shutdown();
|
Rml::Shutdown();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user