mirror of
https://github.com/waydroid/waydroid.git
synced 2026-06-11 18:05:12 -04:00
192 lines
7.2 KiB
Python
192 lines
7.2 KiB
Python
# Copyright 2021 Erfan Abdi
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
import glob
|
|
import logging
|
|
import os
|
|
import threading
|
|
import tools.config
|
|
import tools.helpers.net
|
|
from pathlib import Path
|
|
from tools.interfaces import IUserMonitor
|
|
from tools.interfaces import IPlatform
|
|
from gi.repository import GLib
|
|
|
|
stopping = False
|
|
|
|
def start(args, session, unlocked_cb=None):
|
|
waydroid_data = session["waydroid_data"]
|
|
apps_dir = session["xdg_data_home"] + "/applications/"
|
|
|
|
system_apps = [
|
|
"com.android.calculator2",
|
|
"com.android.camera2",
|
|
"com.android.contacts",
|
|
"com.android.deskclock",
|
|
"com.android.documentsui",
|
|
"com.android.email",
|
|
"com.android.gallery3d",
|
|
"com.android.inputmethod.latin",
|
|
"com.android.settings",
|
|
"com.google.android.gms",
|
|
"org.lineageos.aperture",
|
|
"org.lineageos.eleven",
|
|
"org.lineageos.etar",
|
|
"org.lineageos.jelly",
|
|
"org.lineageos.recorder"
|
|
]
|
|
|
|
|
|
def prepend_list(old_list, new_list):
|
|
for s in reversed(new_list):
|
|
if s not in old_list:
|
|
old_list.insert(0, s)
|
|
|
|
def glib_key_file_get_string_list(key_file, group, key):
|
|
try:
|
|
return key_file.get_string_list(group, key)
|
|
except:
|
|
return []
|
|
|
|
def glib_key_file_prepend_string_list(key_file, group, key, new_list):
|
|
lst = glib_key_file_get_string_list(key_file, group, key)
|
|
prepend_list(lst, new_list)
|
|
key_file.set_string_list(group, key, lst)
|
|
|
|
def glib_key_file_has_value(key_file, group, key):
|
|
try:
|
|
key_file.get_value(group, key)
|
|
return True
|
|
except:
|
|
return False
|
|
|
|
# Migrate waydroid user configs after upgrade
|
|
def user_migration():
|
|
apps_dir = session["xdg_data_home"] + "/applications/"
|
|
state_dir = session["waydroid_user_state"]
|
|
if not any(glob.iglob(f'{apps_dir}/waydroid.*.desktop')):
|
|
# first ever run, no need to migrate
|
|
return
|
|
|
|
if not os.path.exists(os.path.join(state_dir, ".migrated-main-desktop-file")):
|
|
Path(os.path.join(apps_dir, "Waydroid.desktop")).unlink(missing_ok=True)
|
|
Path(os.path.join(state_dir, ".migrated-main-desktop-file")).touch()
|
|
|
|
if not os.path.exists(os.path.join(state_dir, ".migrated-app-settings-desktop-action")):
|
|
for app in glob.iglob(f'{apps_dir}/waydroid.*.desktop'):
|
|
try:
|
|
desktop_file = GLib.KeyFile()
|
|
flags = GLib.KeyFileFlags.KEEP_COMMENTS | GLib.KeyFileFlags.KEEP_TRANSLATIONS
|
|
desktop_file.load_from_file(app, flags)
|
|
try:
|
|
desktop_file.remove_group("Desktop Action app_settings")
|
|
except:
|
|
pass
|
|
try:
|
|
actions = glib_key_file_get_string_list(desktop_file, "Desktop Entry", "Actions")
|
|
actions.remove("app_settings")
|
|
desktop_file.set_string_list("Desktop Entry", "Actions", actions)
|
|
except:
|
|
pass
|
|
desktop_file.save_to_file(app)
|
|
except:
|
|
continue
|
|
Path(os.path.join(state_dir, ".migrated-app-settings-desktop-action")).touch()
|
|
|
|
# Creates, deletes, or updates desktop file
|
|
def updateDesktopFile(appInfo):
|
|
if appInfo is None:
|
|
return
|
|
|
|
showApp = False
|
|
for cat in appInfo["categories"]:
|
|
if cat.strip() == "android.intent.category.LAUNCHER":
|
|
showApp = True
|
|
if not showApp:
|
|
try:
|
|
os.remove(desktop_file_path)
|
|
except:
|
|
pass
|
|
|
|
packageName = appInfo["packageName"]
|
|
|
|
desktop_file_path = apps_dir + "/waydroid." + packageName + ".desktop"
|
|
desktop_file = GLib.KeyFile()
|
|
try:
|
|
flags = GLib.KeyFileFlags.KEEP_COMMENTS | GLib.KeyFileFlags.KEEP_TRANSLATIONS
|
|
desktop_file.load_from_file(desktop_file_path, flags)
|
|
except:
|
|
pass
|
|
|
|
desktop_file.set_string("Desktop Entry", "Type", "Application")
|
|
desktop_file.set_string("Desktop Entry", "Name", appInfo["name"])
|
|
desktop_file.set_string("Desktop Entry", "Exec", f"waydroid app launch {packageName}")
|
|
desktop_file.set_string("Desktop Entry", "Icon", f"{waydroid_data}/icons/{packageName}.png")
|
|
glib_key_file_prepend_string_list(desktop_file, "Desktop Entry", "Categories", ["X-WayDroid-App"])
|
|
desktop_file.set_string_list("Desktop Entry", "X-Purism-FormFactor", ["Workstation", "Mobile"])
|
|
glib_key_file_prepend_string_list(desktop_file, "Desktop Entry", "Actions", ["app-settings"])
|
|
if packageName in system_apps and not glib_key_file_has_value(desktop_file, "Desktop Entry", "NoDisplay"):
|
|
desktop_file.set_boolean("Desktop Entry", "NoDisplay", True)
|
|
|
|
desktop_file.set_string("Desktop Action app-settings", "Name", "App Settings")
|
|
desktop_file.set_string("Desktop Action app-settings", "Exec", f"waydroid app intent android.settings.APPLICATION_DETAILS_SETTINGS package:{packageName}")
|
|
desktop_file.set_string("Desktop Action app-settings", "Icon", f"{waydroid_data}/icons/com.android.settings.png")
|
|
|
|
desktop_file.save_to_file(desktop_file_path)
|
|
|
|
|
|
def userUnlocked(uid):
|
|
cfg = tools.config.load(args)
|
|
logging.info("Android with user {} is ready".format(uid))
|
|
|
|
user_migration()
|
|
|
|
if cfg["waydroid"]["auto_adb"] == "True":
|
|
try:
|
|
tools.helpers.net.adb_connect(args)
|
|
except:
|
|
pass
|
|
|
|
platformService = IPlatform.get_service(args)
|
|
if platformService:
|
|
if not os.path.exists(apps_dir):
|
|
os.mkdir(apps_dir, 0o700)
|
|
appsList = platformService.getAppsInfo()
|
|
for app in appsList:
|
|
updateDesktopFile(app)
|
|
for existing in glob.iglob(f'{apps_dir}/waydroid.*.desktop'):
|
|
if os.path.basename(existing) not in map(lambda appInfo: f"waydroid.{appInfo['packageName']}.desktop", appsList):
|
|
os.remove(existing)
|
|
if unlocked_cb:
|
|
unlocked_cb()
|
|
|
|
def packageStateChanged(mode, packageName, uid):
|
|
platformService = IPlatform.get_service(args)
|
|
if platformService:
|
|
desktop_file_path = apps_dir + "/waydroid." + packageName + ".desktop"
|
|
if mode == IUserMonitor.PACKAGE_REMOVED:
|
|
try:
|
|
os.remove(desktop_file_path)
|
|
except:
|
|
pass
|
|
else:
|
|
appInfo = platformService.getAppInfo(packageName)
|
|
updateDesktopFile(appInfo)
|
|
|
|
def service_thread():
|
|
while not stopping:
|
|
IUserMonitor.add_service(args, userUnlocked, packageStateChanged)
|
|
|
|
global stopping
|
|
stopping = False
|
|
args.user_manager = threading.Thread(target=service_thread)
|
|
args.user_manager.start()
|
|
|
|
def stop(args):
|
|
global stopping
|
|
stopping = True
|
|
try:
|
|
if args.userMonitorLoop:
|
|
args.userMonitorLoop.quit()
|
|
except AttributeError:
|
|
logging.debug("UserMonitor service is not even started")
|