8.0 KiB
Quest App Launcher — Documentation
Table of Contents
- Overview
- Architecture
- Configuration
- App Name Overrides
- Custom Icons
- Tab / Category System
- Asset Auto-Update
- Managed Policies
- On-Device File Locations
Overview
Quest App Launcher is a VR home-screen replacement for Meta Quest 2. It lists all installed non-system apps in a scrollable grid, organized into tabs. Apps can be launched by pointing and clicking with the controller.
Architecture
Data Flow
- AppInfo.java (Android plugin) — queries the Android package manager for installed apps, decodes icons as bitmaps, and reads usage statistics via
UsageStatsManager. - AppProcessor.cs — calls the Java plugin over JNI, applies name overrides from
appnames*.json, filters excluded packages, assigns apps to auto tabs (Quest / 2D), and returns aProcessedAppdictionary. - GridPopulation.cs — takes the processed app list, sorts it (A–Z or most-recently-used), builds tab containers, and instantiates
AppEntryprefab tiles in the grid. - AppEntry.cs — represents a single icon tile. Lazy-loads and unloads its texture based on scroll position to keep memory use bounded.
Key Scripts
| File | Role |
|---|---|
Assets/Scripts/AppProcessor.cs |
App discovery, name overrides, exclusion lists, icon loading |
Assets/Scripts/GridPopulation.cs |
Grid layout, tab assignment, sort order |
Assets/Scripts/AppEntry.cs |
Per-tile icon loading / unloading |
Assets/Scripts/Config.cs |
Settings model and JSON persistence |
Assets/Scripts/AssetsDownloader.cs |
Downloads icon packs and app name files from GitHub |
Assets/Scripts/SkyboxHandler.cs |
Background skybox selection and loading |
Assets/Scripts/SettingsHandler.cs |
Settings UI wiring |
Assets/Scripts/GlobalState.cs |
Cross-scene singleton (DontDestroyOnLoad) |
Assets/Plugins/Android/AppInfo.java |
Android interop layer |
Configuration
Settings are stored in config.json in the app's persistent data path on-device. The file is created with defaults on first run. You can push a custom config.json via adb:
adb push config.json /sdcard/Android/data/dev.oxmc.QuestAppLauncher/files/
config.json fields
| Field | Type | Default | Description |
|---|---|---|---|
gridSize.rows |
int | 3 | Number of rows in the grid |
gridSize.cols |
int | 3 | Number of columns in the grid |
sortMode |
string | "az" |
Sort order: "az" (alphabetical) or "mostRecent" |
show2D |
bool | true |
Whether to show 2D (non-VR) apps |
autoCategory |
string | "top" |
Where auto tabs appear: "top", "left", "right", or "off" |
customCategory |
string | "right" |
Where custom tabs appear: same options as above |
autoUpdate |
bool | true |
Automatically check for and download asset updates |
background |
string | "default" |
Background image path, or "default" for the built-in skybox |
downloadRepos |
array | GitHub default | List of repos to pull icon packs and app names from |
managedPolicyEndpoint |
string | "" |
URL to fetch managed policy JSON from (IT/MDM use) |
Example config.json
{
"gridSize": { "rows": 3, "cols": 4 },
"sortMode": "az",
"show2D": true,
"autoCategory": "top",
"customCategory": "right",
"autoUpdate": true,
"background": "default",
"downloadRepos": [
{ "repoUri": "hooverhigh/QuestAppLauncher_Assets/releases/latest", "type": "github" }
]
}
App Name Overrides
Place appnames.json (or any appnames*.json file) in the persistent data path to rename apps and assign them to custom tabs.
Format (appnames.json)
{
"com.example.myapp": {
"Name": "My App",
"Category": "Games",
"Category2": "Favorites"
}
}
- Name — display name override (leave blank to keep the original name)
- Category / Category2 — optional tab names (up to two per app)
Pushing to the device
adb push appnames.json /sdcard/Android/data/dev.oxmc.QuestAppLauncher/files/
Custom Icons
Place .jpg files named <packageName>.jpg in the persistent data path, or bundle them into a zip file named iconpack*.zip.
Individual icons
adb push com.example.myapp.jpg /sdcard/Android/data/dev.oxmc.QuestAppLauncher/files/
Icon packs (zip)
Create a zip containing <packageName>.jpg files at the root level:
iconpack_custom.zip
com.example.myapp.jpg
com.example.otherapp.jpg
adb push iconpack_custom.zip /sdcard/Android/data/dev.oxmc.QuestAppLauncher/files/
The launcher extracts icon packs automatically on startup. Multiple icon packs are supported and applied in alphabetical order (later packs override earlier ones).
Tab / Category System
Auto tabs
Apps are automatically assigned to one of two built-in tabs based on their package metadata:
| Tab | Criteria |
|---|---|
| Quest | App declares the android.hardware.vr.headtracking feature, or any other VR app |
| 2D | App has no VR features |
The All tab always shows every app regardless of category.
Auto tabs can be placed at the top, left, or right of the panel, or disabled entirely via autoCategory in config.json.
Custom tabs
Assign apps to custom tabs using the Category / Category2 fields in appnames.json. Custom tabs appear sorted alphabetically. Their position is controlled by customCategory in config.json.
Asset Auto-Update
When autoUpdate is true, the launcher checks configured repos for updated icon packs and app name files on startup (rate-limited to once every 5 minutes). If updates are found, they are downloaded to the download_cache folder inside the persistent data path and the scene is reloaded.
Adding a custom HTTP repo
In addition to GitHub releases, you can host assets on any plain HTTP server by providing a manifest JSON:
{
"files": [
{ "name": "iconpack_school.zip", "url": "https://yourserver.com/iconpack_school.zip", "updatedAt": "2025-01-01T00:00:00Z" },
{ "name": "appnames.json", "url": "https://yourserver.com/appnames.json", "updatedAt": "2025-01-01T00:00:00Z" }
]
}
Add it to downloadRepos in config.json:
{ "repoUri": "https://yourserver.com/manifest.json", "type": "http" }
Managed Policies
For IT/MDM deployments, the launcher can fetch a policy JSON from a URL on every startup. Set managedPolicyEndpoint in config.json (or define DEV_ENDPOINT at compile time).
Supported policy fields:
| Field | Type | Description |
|---|---|---|
hiddenApps |
string[] | Package names to hide from the launcher |
appNames |
object | Same format as appnames.json — name/category overrides |
disableSettings |
bool | Hides the settings button |
wallpaper |
string | URL to a background image (overrides user setting) |
On-Device File Locations
All user-editable files live in the app's persistent data path:
/sdcard/Android/data/dev.oxmc.QuestAppLauncher/files/
| File / Folder | Purpose |
|---|---|
config.json |
App settings |
appnames*.json |
App name and category overrides |
iconpack*.zip |
Custom icon packs |
*.jpg |
Individual icon overrides (<packageName>.jpg) |
excludedpackages.txt |
One package name per line — these apps are hidden |
download_cache/ |
Downloaded icon packs and app name files (managed automatically) |
Useful adb commands
# View Unity logs live
adb logcat -s Unity
# List files in persistent data path
adb shell ls /sdcard/Android/data/dev.oxmc.QuestAppLauncher/files/
# Push a config file
adb push config.json /sdcard/Android/data/dev.oxmc.QuestAppLauncher/files/
# Pull all app data (for debugging)
adb pull /sdcard/Android/data/dev.oxmc.QuestAppLauncher/files/ ./device_files