]> glassweightruler.freedombox.rocks Git - waydroid.git/blobdiff - tools/services/user_manager.py
session_manager: Stop the container on SIGHUP
[waydroid.git] / tools / services / user_manager.py
index 3b5ea29e0d568435bd4d0b4c1448a4522a42025f..802472ba03397805b71cb39dec50040f2efe3195 100644 (file)
@@ -1,5 +1,6 @@
 # Copyright 2021 Erfan Abdi
 # SPDX-License-Identifier: GPL-3.0-or-later
+import glob
 import logging
 import os
 import threading
@@ -7,6 +8,7 @@ import tools.config
 import tools.helpers.net
 from tools.interfaces import IUserMonitor
 from tools.interfaces import IPlatform
+from gi.repository import GLib
 
 stopping = False
 
@@ -14,58 +16,124 @@ def start(args, session, unlocked_cb=None):
     waydroid_data = session["waydroid_data"]
     apps_dir = session["xdg_data_home"] + "/applications/"
 
-    def makeDesktopFile(appInfo):
+    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):
+        old_list = glib_key_file_get_string_list(key_file, group, key)
+        prepend_list(old_list, new_list)
+        key_file.set_string_list(group, key, new_list)
+
+    def glib_key_file_has_value(key_file, group, key):
+        try:
+            key_file.get_value(group, key)
+            return True
+        except:
+            return False
+
+
+    # Creates, deletes, or updates desktop file
+    def updateDesktopFile(appInfo):
         if appInfo is None:
-            return -1
+            return
 
         showApp = False
         for cat in appInfo["categories"]:
             if cat.strip() == "android.intent.category.LAUNCHER":
                 showApp = True
         if not showApp:
-            return -1
+            try:
+                os.remove(desktop_file_path)
+            except:
+                pass
 
         packageName = appInfo["packageName"]
 
         desktop_file_path = apps_dir + "/waydroid." + packageName + ".desktop"
-        if not os.path.exists(desktop_file_path):
-            with open(desktop_file_path, "w") as desktop_file:
-                desktop_file.write(f"""\
-[Desktop Entry]
-Type=Application
-Name={appInfo["name"]}
-Exec=waydroid app launch {packageName}
-Icon={waydroid_data}/icons/{packageName}.png
-Categories=X-WayDroid-App;
-X-Purism-FormFactor=Workstation;Mobile;
-Actions=app_settings;
-
-[Desktop Action app_settings]
-Name=App Settings
-Exec=waydroid app intent android.settings.APPLICATION_DETAILS_SETTINGS package:{packageName}
-""")
-            return 0
-
-    def makeWaydroidDesktopFile(hide):
+        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 updateWaydroidDesktopFile(hide):
         desktop_file_path = apps_dir + "/Waydroid.desktop"
-        if os.path.isfile(desktop_file_path):
-            os.remove(desktop_file_path)
-        with open(desktop_file_path, "w") as desktop_file:
-            desktop_file.write(f"""\
-[Desktop Entry]
-Type=Application
-Name=Waydroid
-Exec=waydroid show-full-ui
-Categories=X-WayDroid-App;
-X-Purism-FormFactor=Workstation;Mobile;
-Icon=waydroid
-NoDisplay={str(hide).lower()}
-""")
+        # If the user has set the desktop file as read-only, we won't replace it
+        if os.path.isfile(desktop_file_path) and not os.access(desktop_file_path, os.W_OK):
+            logging.info(f"Desktop file '{desktop_file_path}' is not writeable, not updating it")
+            return
+
+        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", "Waydroid")
+        desktop_file.set_string("Desktop Entry", "Exec", "waydroid show-full-ui")
+        glib_key_file_prepend_string_list(desktop_file, "Desktop Entry", "Categories", ["X-WayDroid-App", "Utility"])
+        desktop_file.set_string_list("Desktop Entry", "X-Purism-FormFactor", ["Workstation", "Mobile"])
+        desktop_file.set_string("Desktop Entry", "Icon", "waydroid")
+        desktop_file.set_boolean("Desktop Entry", "NoDisplay", hide)
+
+        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))
 
-        tools.helpers.net.adb_connect(args)
+        if cfg["waydroid"]["auto_adb"] == "True":
+            try:
+                tools.helpers.net.adb_connect(args)
+            except:
+                pass
 
         platformService = IPlatform.get_service(args)
         if platformService:
@@ -73,27 +141,27 @@ NoDisplay={str(hide).lower()}
                 os.mkdir(apps_dir, 0o700)
             appsList = platformService.getAppsInfo()
             for app in appsList:
-                makeDesktopFile(app)
+                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)
             multiwin = platformService.getprop("persist.waydroid.multi_windows", "false")
-            makeWaydroidDesktopFile(multiwin == "true")
+            updateWaydroidDesktopFile(multiwin == "true")
         if unlocked_cb:
             unlocked_cb()
 
     def packageStateChanged(mode, packageName, uid):
         platformService = IPlatform.get_service(args)
         if platformService:
-            appInfo = platformService.getAppInfo(packageName)
             desktop_file_path = apps_dir + "/waydroid." + packageName + ".desktop"
-            if mode == 0:
-                # Package added
-                makeDesktopFile(appInfo)
-            elif mode == 1:
-                if os.path.isfile(desktop_file_path):
+            if mode == IUserMonitor.PACKAGE_REMOVED:
+                try:
                     os.remove(desktop_file_path)
+                except:
+                    pass
             else:
-                if os.path.isfile(desktop_file_path):
-                    if makeDesktopFile(appInfo) == -1:
-                        os.remove(desktop_file_path)
+                appInfo = platformService.getAppInfo(packageName)
+                updateDesktopFile(appInfo)
 
     def service_thread():
         while not stopping: