A lightweight Android app that automatically manages network connections based on your network type (mobile data vs WiFi).
Now supports TWO automation modes:
- 🦊 Tailscale VPN - Automatic VPN connection management
- 🔒 Private DNS - Automatic DNS-over-TLS configuration (NEW!)
- 🔄 Dual Automation Modes: Choose between Tailscale VPN or Private DNS
- ⚡ Private DNS Mode: Instant DNS switching without app interruption
- 🦊 Tailscale Mode: Automatic VPN connection management
- ⏱️ Smart Debouncing: Prevents spam operations within 30-second windows
- 🔧 Manual Controls: Test connections manually with dedicated buttons
- 📱 Foreground Service: Reliable background operation with persistent notification
- 🔄 Auto-restart: Survives device reboots when automation is enabled
- 🎨 Modern UI: Clean Compose interface with status indicators and mode selector
- 🖼️ Edge-to-Edge Display: Full-screen immersive UI following Android 15 guidelines
- Android: API 24+ (Android 7.0+)
- Tailscale App: Must be installed and configured
- Permissions: Network state, WiFi state, foreground service, boot completed
- Android: API 29+ (Android 10.0+)
- ADB Access: One-time permission grant via ADB
- Permissions: Network state, WiFi state, foreground service, boot completed, WRITE_SECURE_SETTINGS
# Install Java (if not already installed)
brew install openjdk@17
# Install Android SDK tools
brew install android-commandlinetools android-platform-tools
# Set up environment (add to ~/.zshrc)
export ANDROID_HOME=/opt/homebrew/share/android-commandlinetools
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools
export PATH="/opt/homebrew/opt/gradle@8/bin:$PATH"
# Accept SDK licenses
yes | sdkmanager --licenses
# Install required SDK components
sdkmanager "platform-tools" "platforms;android-34" "build-tools;33.0.2"./gradlew assembleDebugConnect your Android device with USB debugging enabled, then:
# Find your device
adb devices
# Install the APK
adb install app/build/outputs/apk/debug/app-debug.apk- Install Tailscale: Make sure Tailscale app is installed and logged in
- Launch App: Open "Antomate"
- Select Mode: Choose "Tailscale" in the Automation Mode card
- Enable Automation: Toggle "Enable Automation" switch
- Grant Permissions: Allow network and notification permissions
- Monitor Status: Watch the status indicators
How it works:
- Mobile Data → Connect: Sends CONNECT_VPN broadcast to Tailscale
- WiFi → Disconnect: Sends DISCONNECT_VPN broadcast to Tailscale
- User Experience: Brief 2.5s app switch, returns to previous app automatically
-
Grant ADB Permission (one-time setup):
adb shell pm grant io.github.jollysleeper.antomate android.permission.WRITE_SECURE_SETTINGS
-
Configure DNS:
- Launch "Antomate"
- Select "Private DNS" in Automation Mode card
- Enter your DNS hostname (e.g.,
dns.adguard.com,dns.google) - Tap "Save DNS Hostname"
-
Enable Automation: Toggle "Enable Automation" switch
-
Enjoy: DNS switches instantly without any app interruption!
How it works:
- Mobile Data → Enable DNS: Configures Private DNS with your hostname
- WiFi → Disable DNS: Turns off Private DNS
- User Experience: Instant, no visible interruption
📖 See PRIVATE_DNS_SETUP.md for detailed setup guide
- Connect Now: Manually trigger VPN connection
- Disconnect Now: Manually trigger VPN disconnection
- Open Tailscale: Launch Tailscale app directly
- Enable DNS: Manually enable Private DNS
- Disable DNS: Manually disable Private DNS
- Check Tailscale: Ensure Tailscale app is installed and authenticated
- Verify Permissions: Grant all requested permissions
- Check Logs: Use
adb logcat | grep -i tailscaleto see broadcast attempts - Manual Test: Try manual connect/disconnect buttons first
- Battery Optimization: Add app to battery optimization exceptions
- Settings → Apps → [App Name] → Battery → Don't optimize
- Background Restrictions: Disable any OEM battery savers for this app
- Force Stop Test: Try manual service start/stop buttons
Xiaomi/HyperOS:
# Disable battery optimization
Settings → Apps → [App Name] → Battery saver → No restrictionsSamsung:
# Disable adaptive battery
Settings → Apps → [App Name] → Battery → Optimize battery usage → Don't optimizeOnePlus/HydrogenOS:
# Recent apps → [App icon] → Lock (padlock icon)# View app logs
adb logcat | grep -i "tailscale\|NetworkMonitor"
# View all broadcasts
adb logcat | grep -i "broadcast"
# Check service status
adb shell dumpsys activity services | grep NetworkMonitorThe app sends explicit broadcasts to Tailscale:
// Connect VPN
Intent("com.tailscale.ipn.CONNECT_VPN").apply {
component = ComponentName("com.tailscale.ipn", "com.tailscale.ipn.IPNReceiver")
}
// Disconnect VPN
Intent("com.tailscale.ipn.DISCONNECT_VPN").apply {
component = ComponentName("com.tailscale.ipn", "com.tailscale.ipn.IPNReceiver")
}- UI Layer: Jetpack Compose + ViewModel
- Data Layer: DataStore Preferences for settings
- Service Layer: Foreground service with NetworkCallback
- Broadcast Layer: Explicit intents to Tailscale
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />- App Switching: 2.5s visible interruption when launching Tailscale
- Tailscale Dependency: Requires Tailscale app to be installed
- Broadcast Compatibility: May break if Tailscale changes their broadcast API
- ADB Requirement: One-time setup requires computer with ADB
- DNS Only: No VPN tunneling, only DNS queries are affected
- Android 9+ Only: Older devices not supported
- OEM Restrictions: Some manufacturers heavily restrict background services
- WiFi SSID Filtering: Current version connects/disconnects on any WiFi (SSID whitelist in future version)
- Location Permission: Not required in current version (needed for SSID detection in future)
app/
├── src/main/
│ ├── AndroidManifest.xml
│ ├── java/com/antomate/tailscale/
│ │ ├── MainActivity.kt # Compose UI
│ │ ├── MainViewModel.kt # UI state management
│ │ ├── service/
│ │ │ ├── NetworkMonitorService.kt # Foreground service
│ │ │ ├── NetworkMonitor.kt # Network detection
│ │ │ └── TailscaleController.kt # Broadcast sender
│ │ ├── data/
│ │ │ ├── SettingsRepository.kt # DataStore wrapper
│ │ │ └── AppSettings.kt # Data classes
│ │ └── receiver/
│ │ └── BootReceiver.kt # Auto-start on boot
│ └── res/ # Resources
└── build.gradle.kts # Dependencies
# Run unit tests
./gradlew testDebugUnitTest
# Run instrumentation tests (requires device/emulator)
./gradlew connectedDebugAndroidTestThis project is provided as-is for educational and personal use.
- Fork the repository
- Create a feature branch
- Make changes with tests
- Submit a pull request
If you're frustrated with Tailscale's unreliable broadcast receiver and the annoying app-switching behavior, Private DNS mode is your solution!
- ✅ No app interruption - Changes happen instantly in the background
- ✅ More reliable - Direct system API calls, no dependency on Tailscale app
- ✅ Faster - No 2.5s delay waiting for Tailscale to launch
- ✅ Less battery usage - No need to launch another app
- ✅ Great for ad-blocking - Use DNS-based ad blockers like AdGuard DNS
Use Tailscale Mode if:
- You need full VPN tunneling (not just DNS)
- You want encrypted traffic routing through Tailscale network
- You're okay with the brief app-switching interruption
Use Private DNS Mode if:
- You mainly want DNS-based features (ad blocking, privacy DNS)
- You want instant, seamless switching
- You're tired of Tailscale's app-switching behavior
- You have access to ADB for one-time setup
- WiFi SSID whitelist/blacklist
- Advanced diagnostics page
- Log export functionality
- Retry logic with exponential backoff
- VpnService fallback for direct VPN control
- Per-SSID automation rules
- Different DNS servers for different WiFi networks