#!/bin/bash ################################################################################ # File Name : debian-waydroid-advanced-aria2.sh # Description : Waydroid AppVM and DispVM setup for Qubes OS with Debian # minimal. Creates a secure Android environment with choice of # VANILLA or GApps Android images. Features include network via # NFTables, fullscreen Sway compositor, bidirectional clipboard # sync, APK installation scripts, and desktop integration. This # script uses aria2 for instable or slow network stacks. # Usage : • Transfer to dom0: # qvm-run -p appvm 'cat ~/debian-waydroid-advanced-aria2.sh' > ~/debian-waydroid-advanced-aria2.sh # • Make executable: # chmod +x ~/debian-waydroid-advanced-aria2.sh # • Run: # bash ~/debian-waydroid-advanced-aria2.sh # Author : Based on apparatus guide from Qubes OS Forum and the bois # License : Free of charge, no warranty # Last edited : 2025-11-02 ################################################################################ # Safety first set -euo pipefail # Configuration (set default values here) APPVM_NAME="waydroid" NAMED_DISP_VM="disp-waydroid" BASE_TEMPLATE="debian-12-minimal" WAYDROID_CUSTOM_TEMPLATE="debian-waydroid-template" WAYDROID_DISP_TEMPLATE="debian-waydroid-template-dvm" WAYDROID_IMAGE_TYPE="waydroid init -s GApps" # Android image with GApps support # WAYDROID_IMAGE_TYPE="waydroid init" # VANILLA Android image NET_VM="sys-whonix" # Whonix may cause issues # Step 1: Verify and create base template create_base_template() { echo -e "\nStep 1: Setting up base template $BASE_TEMPLATE..." if ! qvm-check "$BASE_TEMPLATE" 2>/dev/null; then echo "Installing $BASE_TEMPLATE..." sudo qubes-dom0-update "qubes-template-$BASE_TEMPLATE" fi # Ensure template is shut down before updating qvm-shutdown --wait "$BASE_TEMPLATE" 2>/dev/null || true if qvm-check "$BASE_TEMPLATE"; then echo "Updating $BASE_TEMPLATE..." sudo qubesctl --show-output --skip-dom0 --targets="$BASE_TEMPLATE" state.sls update.qubes-vm fi echo -e "\nBase template setup complete" } # Step 2: Create custom base template create_waydroid_custom_template() { echo -e "\nStep 2: Creating $WAYDROID_CUSTOM_TEMPLATE..." if qvm-check "$WAYDROID_CUSTOM_TEMPLATE"; then echo "$WAYDROID_CUSTOM_TEMPLATE already exists, skipping creation" return 0 fi echo "Cloning $BASE_TEMPLATE to $WAYDROID_CUSTOM_TEMPLATE..." qvm-clone "$BASE_TEMPLATE" "$WAYDROID_CUSTOM_TEMPLATE" qvm-prefs "$WAYDROID_CUSTOM_TEMPLATE" label black echo -e "\nWaydroid template created" } # Step 3: Install packages in Waydroid template (change as needed) install_template_packages() { echo -e "\nStep 3: Installing packages in $WAYDROID_CUSTOM_TEMPLATE..." qvm-start --skip-if-running "$WAYDROID_CUSTOM_TEMPLATE" # Basic system configuration echo "Configuring system environment..." qvm-run -p -u root "$WAYDROID_CUSTOM_TEMPLATE" "echo 'TERM=xterm' >> /etc/environment" qvm-run -p -u root "$WAYDROID_CUSTOM_TEMPLATE" "sed -i 's/^# *\(en_US.UTF-8\)/\1/' /etc/locale.gen" qvm-run -p -u root "$WAYDROID_CUSTOM_TEMPLATE" "locale-gen en_US.UTF-8" # Install core packages echo "Installing core packages..." qvm-run -p -u root "$WAYDROID_CUSTOM_TEMPLATE" " apt-get install -y --no-install-recommends \ curl \ ca-certificates \ software-properties-common \ qubes-core-agent-networking \ qubes-core-agent-passwordless-root \ thunar \ qubes-core-agent-thunar \ wireplumber \ pulseaudio-qubes \ less \ psmisc \ xfce4-terminal " } # Function: Install Waydroid and aria2 for faster downloads install_waydroid_packages() { echo -e "\nInstalling Waydroid..." qvm-run -p -u root "$WAYDROID_CUSTOM_TEMPLATE" " export DEBIAN_FRONTEND=noninteractive export http_proxy=http://127.0.0.1:8082 export https_proxy=http://127.0.0.1:8082 # Install extrepo and enable Waydroid repository apt-get install -y extrepo extrepo enable waydroid apt-get update # Install Waydroid core packages apt-get install -y \ waydroid \ sway \ xclip \ wl-clipboard \ x11-utils \ build-essential \ libx11-dev \ libxtst-dev \ python3 \ python3-venv \ python3-pip \ unzip \ aria2 " } # Step 4: Configure Waydroid container service configure_waydroid_service() { echo -e "\nStep 4: Configuring Waydroid container service..." local temp_script=$(mktemp) cat > "$temp_script" << 'EOF' #!/bin/bash mkdir -p /etc/systemd/system/waydroid-container.service.d cat > /etc/systemd/system/waydroid-container.service.d/override.conf << 'INNEREOF' [Unit] ConditionPathExists=!/run/qubes/this-is-templatevm INNEREOF EOF qvm-copy-to-vm "$WAYDROID_CUSTOM_TEMPLATE" "$temp_script" qvm-run -p -u root "$WAYDROID_CUSTOM_TEMPLATE" "bash '/home/user/QubesIncoming/dom0/$(basename $temp_script)'" qvm-run -p -u root "$WAYDROID_CUSTOM_TEMPLATE" "rm -f '/home/user/QubesIncoming/dom0/$(basename $temp_script)'" rm -f "$temp_script" echo "Waydroid service configured" } # Step 5: Install clipboard support install_clipboard_support() { echo -e "\nStep 5: Installing clipboard support..." # Download and build clipnotify qvm-run -p -u root "$WAYDROID_CUSTOM_TEMPLATE" " export DEBIAN_FRONTEND=noninteractive export http_proxy=http://127.0.0.1:8082 export https_proxy=http://127.0.0.1:8082 # Download clipnotify sources curl -L -o /tmp/clipnotify-master.zip https://codeload.github.com/cdown/clipnotify/zip/refs/heads/master unzip -j /tmp/clipnotify-master.zip -d /tmp/clipnotify cd /tmp/clipnotify # Build and install mkdir -p /opt/bin sed -i \"s|/usr/local|/opt|g\" Makefile make make install rm -rf /tmp/clipnotify* " # Create clipboard synchronization script local temp_script=$(mktemp) cat > "$temp_script" << 'EOF' #!/bin/bash x11_wl='while DISPLAY=":0" clipnotify -s clipboard; do xclip -d ".0" -selection clipboard -o | wl-copy; done' wl_x11='wl-paste -nw xclip -d ".0" -selection clipboard' eval "${x11_wl}" &>/dev/null & eval "${wl_x11}" &>/dev/null pstree -A -p $$ | grep -Eow "[0-9]+" | xargs kill &>/dev/null EOF qvm-copy-to-vm "$WAYDROID_CUSTOM_TEMPLATE" "$temp_script" qvm-run -p -u root "$WAYDROID_CUSTOM_TEMPLATE" " mv '/home/user/QubesIncoming/dom0/$(basename $temp_script)' /opt/bin/x11-wl-clip.sh chmod +x /opt/bin/x11-wl-clip.sh mkdir -p /etc/sway/config.d echo 'exec /opt/bin/x11-wl-clip.sh' > /etc/sway/config.d/99-x11-wl-clip.conf echo 'export PATH=\"/opt/bin:$PATH\"' > /etc/profile.d/opt-bin.sh " rm -f "$temp_script" echo "Clipboard support installed" } # Step 6: Install pyclip for Waydroid install_pyclip() { echo -e "\nStep 6: Installing pyclip..." qvm-run -p -u root "$WAYDROID_CUSTOM_TEMPLATE" " export DEBIAN_FRONTEND=noninteractive export http_proxy=http://127.0.0.1:8082 export https_proxy=http://127.0.0.1:8082 python3 -m venv /opt/venv/pyclip source /opt/venv/pyclip/bin/activate pip install --no-cache-dir pyclip deactivate echo 'export PATH=\"\$PATH:/opt/venv/pyclip/bin\"' > /etc/profile.d/python-venv.sh echo 'export PYTHONPATH=\"\$PYTHONPATH:/opt/venv/pyclip/lib/python3.11/site-packages\"' >> /etc/profile.d/python-venv.sh " echo "Pyclip installed" } # Step 7: Configure firewall for Waydroid configure_firewall() { echo -e "\nStep 7: Configuring firewall..." # Create firewall service file local temp_script=$(mktemp) cat > "$temp_script" << 'EOF' #!/bin/bash cat > /etc/systemd/system/waydroid-firewall.service << 'INNEREOF' [Unit] ConditionPathExists=!/run/qubes/this-is-templatevm PartOf=waydroid-container.service After=waydroid-container.service BindsTo=waydroid-container.service Requires=qubes-iptables.service After=qubes-iptables.service BindsTo=qubes-iptables.service [Service] Type=oneshot ExecStart=/usr/bin/bash -c "if (nft create chain ip qubes waydroid-input) 2>/dev/null; then nft add rule ip qubes custom-input jump waydroid-input; fi" ExecStart=/usr/bin/bash -c "if (nft create chain ip qubes waydroid-forward) 2>/dev/null; then nft add rule ip qubes custom-forward jump waydroid-forward; fi" ExecStart=/usr/sbin/nft add rule ip qubes waydroid-input iifname "waydroid0" meta l4proto {tcp, udp} th dport { 53, 67 } accept ExecStart=/usr/sbin/nft add rule ip qubes waydroid-forward iifname "waydroid0" oifgroup 1 accept ExecStart=/usr/sbin/nft add rule ip qubes waydroid-forward oifname "waydroid0" iifgroup 1 accept ExecStop=/usr/sbin/nft flush chain ip qubes waydroid-input ExecStop=/usr/sbin/nft flush chain ip qubes waydroid-forward RemainAfterExit=yes [Install] WantedBy=waydroid-container.service INNEREOF systemctl daemon-reload systemctl enable waydroid-firewall.service EOF qvm-copy-to-vm "$WAYDROID_CUSTOM_TEMPLATE" "$temp_script" qvm-run -p -u root "$WAYDROID_CUSTOM_TEMPLATE" "bash '/home/user/QubesIncoming/dom0/$(basename $temp_script)'" qvm-run -p -u root "$WAYDROID_CUSTOM_TEMPLATE" "rm -f '/home/user/QubesIncoming/dom0/$(basename $temp_script)'" rm -f "$temp_script" echo "Firewall configured" } # Step 8: Configure Sway for fullscreen Waydroid configure_sway() { echo -e "\nStep 8: Configuring Sway..." qvm-run -p -u root "$WAYDROID_CUSTOM_TEMPLATE" " echo 'default_border none' > /etc/sway/config.d/94-disable-window-titlebar.conf # Remove status bar from default config if it exists if [ -f /etc/sway/config ]; then sed -i '/^bar {/,/^}/d' /etc/sway/config fi " echo "Sway configured" } # Step 9: Create Waydroid scripts create_startup_scripts() { echo -e "\nStep 9: Creating Waydroid scripts..." # Create main Waydroid startup script local temp_script1=$(mktemp) cat > "$temp_script1" << 'EOF' #!/bin/bash sway &>/dev/null & WAYLAND_DISPLAY="wayland-1" XDG_SESSION_TYPE="wayland" DISPLAY=":1" waydroid first-launch &>/dev/null & for i in $(seq 1 3); do if xwininfo -name "wlroots - X11-1" &>/dev/null; then break fi sleep 1 done while xwininfo -name "wlroots - X11-1" &>/dev/null; do sleep 2 done WAYLAND_DISPLAY="wayland-1" XDG_SESSION_TYPE="wayland" DISPLAY=":1" waydroid session stop &>/dev/null pstree -A -p $$ | grep -Eow "[0-9]+" | xargs kill &>/dev/null EOF # Create APK installation script local temp_script2=$(mktemp) cat > "$temp_script2" << 'EOF' #!/bin/sh WAYLAND_DISPLAY="wayland-1" XDG_SESSION_TYPE="wayland" DISPLAY=":1" waydroid app install "$1" EOF # Create upgrade script local temp_script3=$(mktemp) cat > "$temp_script3" << 'EOF' #!/bin/sh export http_proxy=http://127.0.0.1:8082 export https_proxy=http://127.0.0.1:8082 waydroid upgrade EOF # Copy all scripts to the template qvm-copy-to-vm "$WAYDROID_CUSTOM_TEMPLATE" "$temp_script1" "$temp_script2" "$temp_script3" qvm-run -p -u root "$WAYDROID_CUSTOM_TEMPLATE" " mv '/home/user/QubesIncoming/dom0/$(basename $temp_script1)' /opt/bin/sway-waydroid.sh mv '/home/user/QubesIncoming/dom0/$(basename $temp_script2)' /opt/bin/waydroid-install-apk mv '/home/user/QubesIncoming/dom0/$(basename $temp_script3)' /opt/bin/waydroid-upgrade chmod +x /opt/bin/sway-waydroid.sh /opt/bin/waydroid-install-apk /opt/bin/waydroid-upgrade rmdir '/home/user/QubesIncoming/dom0' 2>/dev/null || true rmdir '/home/user/QubesIncoming' 2>/dev/null || true " rm -f "$temp_script1" "$temp_script2" "$temp_script3" echo "Startup scripts created" } # Step 10: Create desktop entry create_desktop_entry() { echo -e "\nStep 10: Creating desktop entry..." local temp_script=$(mktemp) cat > "$temp_script" << 'EOF' #!/bin/bash cat > /usr/share/applications/Waydroid-Sway.desktop << 'INNEREOF' [Desktop Entry] Type=Application Name=Waydroid-Sway Exec=/opt/bin/sway-waydroid.sh Icon=waydroid Categories=X-WayDroid-App; X-Purism-FormFactor=Workstation;Mobile; INNEREOF EOF qvm-copy-to-vm "$WAYDROID_CUSTOM_TEMPLATE" "$temp_script" qvm-run -p -u root "$WAYDROID_CUSTOM_TEMPLATE" "bash '/home/user/QubesIncoming/dom0/$(basename $temp_script)'" qvm-run -p -u root "$WAYDROID_CUSTOM_TEMPLATE" "rm -f '/home/user/QubesIncoming/dom0/$(basename $temp_script)'" rm -f "$temp_script" echo "Desktop entry created" } # Step 11: Initialize Waydroid with aria2 initialize_waydroid() { echo -e "\nStep 11: Initializing $WAYDROID_CUSTOM_TEMPLATE..." qvm-start --skip-if-running "$WAYDROID_CUSTOM_TEMPLATE" # Check if already initialized echo "Checking if Waydroid is already initialized..." local waydroid_initialized waydroid_initialized=$(qvm-run -p "$WAYDROID_CUSTOM_TEMPLATE" " if [ -f /var/lib/waydroid/images/system.img ]; then echo '1' else echo '0' fi ") if [[ "$waydroid_initialized" -eq 1 ]]; then echo "Waydroid is already initialized. Skipping download." qvm-shutdown --wait "$WAYDROID_CUSTOM_TEMPLATE" return 0 fi # Determine image type if [[ "$WAYDROID_IMAGE_TYPE" == *"GApps"* ]]; then local image_type="GAPPS" echo "Setting up Waydroid with latest GApps image..." else local image_type="VANILLA" echo "Setting up Waydroid with latest Vanilla image..." fi # Create download script with aria2 local temp_script=$(mktemp) cat > "$temp_script" << EOF #!/bin/bash set -e IMAGE_TYPE="$image_type" echo "[+] Finding latest \$IMAGE_TYPE images from SourceForge..." # Create directories mkdir -p /etc/waydroid-extra/images cd /etc/waydroid-extra/images # Function to extract latest files extract_latest_files() { local image_type="\$1" # System images URL local system_url="https://sourceforge.net/projects/waydroid/files/images/system/lineage/waydroid_x86_64/" # Vendor images URL local vendor_url="https://sourceforge.net/projects/waydroid/files/images/vendor/waydroid_x86_64/" # Get system page and extract filenames local system_content=\$(curl -s -L "\$system_url") # Extract system filenames that match the pattern and image type local system_files=\$(echo "\$system_content" | grep -o 'lineage-[0-9.-]*'"\${image_type}"'-[^"]*-system.zip' | sort -Vr) # Get vendor page and extract filenames local vendor_content=\$(curl -s -L "\$vendor_url") # Extract vendor filenames (vendor doesn't have GAPPS/VANILLA distinction) local vendor_files=\$(echo "\$vendor_content" | grep -o 'lineage-[0-9.-]*-[^"]*-vendor.zip' | sort -Vr) # Get the first (latest) file from each list local system_file=\$(echo "\$system_files" | head -1) local vendor_file=\$(echo "\$vendor_files" | head -1) echo "\$system_file|\$vendor_file" } # Get latest files file_info=\$(extract_latest_files "\$IMAGE_TYPE") system_file=\$(echo "\$file_info" | cut -d'|' -f1) vendor_file=\$(echo "\$file_info" | cut -d'|' -f2) if [[ -z "\$system_file" ]]; then echo "ERROR: No system image found for \$IMAGE_TYPE" echo "Trying to find any available system images..." curl -s -L "https://sourceforge.net/projects/waydroid/files/images/system/lineage/waydroid_x86_64/" | grep -o 'lineage-[^"]*-system.zip' | head -5 exit 1 fi echo "[+] Latest system image: \$system_file" if [[ -n "\$vendor_file" ]]; then echo "[+] Latest vendor image: \$vendor_file" else echo "[!] No vendor image found, checking for any vendor images..." vendor_file=\$(curl -s -L "https://sourceforge.net/projects/waydroid/files/images/vendor/waydroid_x86_64/" | grep -o 'lineage-[^"]*-vendor.zip' | sort -Vr | head -1) if [[ -n "\$vendor_file" ]]; then echo "[+] Found vendor image: \$vendor_file" fi fi # Download function with aria2 download() { local filename="\$1" local output="\$2" local file_type="\$3" # system or vendor # Determine the correct URL based on file type if [[ "\$file_type" == "system" ]]; then local direct_url="https://downloads.sourceforge.net/project/waydroid/images/system/lineage/waydroid_x86_64/\$filename" else local direct_url="https://downloads.sourceforge.net/project/waydroid/images/vendor/waydroid_x86_64/\$filename" fi echo "[+] Downloading \$filename with aria2..." # Use aria2 with progress indication aria2c \ --download-result=hide \ --summary-interval=0 \ --max-connection-per-server=16 \ --split=16 \ --min-split-size=1M \ --file-allocation=prealloc \ --continue=true \ --check-integrity=true \ --max-tries=5 \ --retry-wait=10 \ --timeout=600 \ --max-file-not-found=3 \ --out="\$output" \ "\$direct_url" if [[ \$? -eq 0 ]]; then echo "[+] Download completed: \$filename" return 0 else echo "ERROR: Download failed: \$filename" return 1 fi } # Download system image with aria2 download "\$system_file" "system.zip" "system" # Extract system image echo "[+] Extracting system image..." if unzip -o system.zip system.img 2>/dev/null; then rm -f system.zip echo "[+] System image extracted successfully" else # If unzip fails, try to see if it's already an image if file system.zip | grep -q "Android sparse image"; then mv system.zip system.img echo "[+] File is already Android sparse image" else echo "ERROR: Failed to extract system image from system.zip" exit 1 fi fi # Download vendor image if available if [[ -n "\$vendor_file" ]]; then download "\$vendor_file" "vendor.zip" "vendor" echo "[+] Extracting vendor image..." if unzip -o vendor.zip vendor.img 2>/dev/null; then rm -f vendor.zip echo "[+] Vendor image extracted successfully" else # If unzip fails, try to see if it's already an image if file vendor.zip | grep -q "Android sparse image"; then mv vendor.zip vendor.img echo "[+] File is already Android sparse image" else echo "ERROR: Failed to extract vendor image from vendor.zip" exit 1 fi fi fi # Verify downloaded images echo "[+] Verifying downloaded images..." if [[ -f "system.img" ]]; then system_size=\$(du -h system.img | cut -f1) echo "[+] System image ready: \$system_size" else echo "ERROR: System image download failed" exit 1 fi if [[ -f "vendor.img" ]]; then vendor_size=\$(du -h vendor.img | cut -f1) echo "[+] Vendor image ready: \$vendor_size" fi # Stop waydroid if running systemctl stop waydroid-container 2>/dev/null || true # Copy images to Waydroid directory echo "[+] Installing images to Waydroid data directory..." mkdir -p /var/lib/waydroid/images cp system.img /var/lib/waydroid/images/ if [[ -f vendor.img ]]; then cp vendor.img /var/lib/waydroid/images/ fi # Set proper permissions chmod 644 /var/lib/waydroid/images/*.img # Initialize Waydroid with existing images echo "[+] Initializing Waydroid with local images..." if [[ -f vendor.img ]]; then waydroid init -f else # If no vendor image, still try to initialize waydroid init -f fi # Verify initialization if waydroid status 2>/dev/null | grep -q "CONTAINER"; then echo "[+] Waydroid initialized successfully with latest \$IMAGE_TYPE images" else echo "[+] Waydroid initialization completed" waydroid status || true fi EOF # Copy and execute the script echo "Downloading latest Waydroid images with aria2..." qvm-copy-to-vm "$WAYDROID_CUSTOM_TEMPLATE" "$temp_script" qvm-run -p -u root "$WAYDROID_CUSTOM_TEMPLATE" " export http_proxy=http://127.0.0.1:8082 export https_proxy=http://127.0.0.1:8082 bash /home/user/QubesIncoming/dom0/$(basename "$temp_script") " local result=$? # Clean up qvm-run -p "$WAYDROID_CUSTOM_TEMPLATE" "rm -f /home/user/QubesIncoming/dom0/$(basename "$temp_script")" 2>/dev/null || true rm -f "$temp_script" if [ $result -eq 0 ]; then echo "Waydroid initialization completed successfully with latest images" else echo "ERROR: Waydroid initialization failed" return 1 fi qvm-shutdown --wait "$WAYDROID_CUSTOM_TEMPLATE" } # Step 12: Create AppVM create_appvm() { echo -e "\nStep 12: Creating AppVM $APPVM_NAME..." if qvm-check "$APPVM_NAME"; then echo "$APPVM_NAME already exists, skipping creation" return 0 fi echo "Creating AppVM from template $WAYDROID_CUSTOM_TEMPLATE..." qvm-create --template "$WAYDROID_CUSTOM_TEMPLATE" --label green \ --property netvm="$NET_VM" \ --property provides_network=False \ --property vcpus=2 \ --property memory=1024 \ --property maxmem=2048 \ --property autostart=False \ --property include_in_backups=False \ "$APPVM_NAME" echo "AppVM $APPVM_NAME created successfully" } # Step 13: Create DVM template based on custom template create_dispvm_template() { echo -e "\nStep 13: Creating DVM template..." qvm-create --template "$WAYDROID_CUSTOM_TEMPLATE" --label red "$WAYDROID_DISP_TEMPLATE" qvm-prefs "$WAYDROID_DISP_TEMPLATE" template_for_dispvms True } # Step 14: Create named disposable VM instance create_named_disposable() { echo -e "\nStep 14: Creating named disposable VM instance..." if ! qvm-check "$NAMED_DISP_VM" 2>/dev/null; then qvm-create --class DispVM --template "$WAYDROID_DISP_TEMPLATE" --label red \ --property netvm="$NET_VM" \ --property provides_network=False \ --property vcpus=2 \ --property memory=1024 \ --property maxmem=2048 \ --property autostart=False \ --property include_in_backups=False \ "$NAMED_DISP_VM" qvm-features "$NAMED_DISP_VM" appmenus-dispvm 1 else echo "Named disposable already exists, skipping creation." fi } # Finalize finalize() { echo -e "\nFinalizing..." qvm-start --skip-if-running "$WAYDROID_CUSTOM_TEMPLATE" qvm-sync-appmenus "$WAYDROID_CUSTOM_TEMPLATE" qvm-shutdown --wait "$WAYDROID_CUSTOM_TEMPLATE" qvm-features "$WAYDROID_CUSTOM_TEMPLATE" menu-items "Waydroid-Sway.desktop thunar.desktop debian-xterm.desktop xfce4-terminal.desktop" qvm-features "$APPVM_NAME" menu-items "Waydroid-Sway.desktop thunar.desktop debian-xterm.desktop xfce4-terminal.desktop" qvm-features "$WAYDROID_DISP_TEMPLATE" menu-items "Waydroid-Sway.desktop thunar.desktop debian-xterm.desktop xfce4-terminal.desktop" qvm-features "$NAMED_DISP_VM" menu-items "Waydroid-Sway.desktop thunar.desktop debian-xterm.desktop xfce4-terminal.desktop" } # Main execution function main() { echo "Starting Waydroid setup..." create_base_template create_waydroid_custom_template install_template_packages install_waydroid_packages configure_waydroid_service install_clipboard_support install_pyclip configure_firewall configure_sway create_startup_scripts create_desktop_entry initialize_waydroid create_appvm create_dispvm_template create_named_disposable finalize echo -e "\nSetup completed!" } # Run main function main "$@"