fix: switch to dynamic shortcuts

closes #365
closes #508
This commit is contained in:
Zane Schepke 2024-12-21 23:28:50 -05:00
parent 133bd6caf7
commit 7cf7817cea
8 changed files with 101 additions and 78 deletions

View File

@ -79,9 +79,6 @@
<category android:name="android.intent.category.LEANBACK_LAUNCHER" /> <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" /> <action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
</intent-filter> </intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
</activity> </activity>
<activity <activity
android:name="com.journeyapps.barcodescanner.CaptureActivity" android:name="com.journeyapps.barcodescanner.CaptureActivity"

View File

@ -5,6 +5,8 @@ import com.zaneschepke.logcatter.LogReader
import com.zaneschepke.logcatter.LogcatReader import com.zaneschepke.logcatter.LogcatReader
import com.zaneschepke.wireguardautotunnel.service.notification.NotificationService import com.zaneschepke.wireguardautotunnel.service.notification.NotificationService
import com.zaneschepke.wireguardautotunnel.service.notification.WireGuardNotification import com.zaneschepke.wireguardautotunnel.service.notification.WireGuardNotification
import com.zaneschepke.wireguardautotunnel.service.shortcut.DynamicShortcutManager
import com.zaneschepke.wireguardautotunnel.service.shortcut.ShortcutManager
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
@ -35,4 +37,10 @@ class AppModule {
fun provideNotificationService(@ApplicationContext context: Context): NotificationService { fun provideNotificationService(@ApplicationContext context: Context): NotificationService {
return WireGuardNotification(context) return WireGuardNotification(context)
} }
@Singleton
@Provides
fun provideShortcutManager(@ApplicationContext context: Context): ShortcutManager {
return DynamicShortcutManager(context)
}
} }

View File

@ -264,7 +264,7 @@ class AutoTunnelService : LifecycleService() {
wifi.available, wifi.available,
mobileData.available, mobileData.available,
false, false,
wifi.name wifi.name,
) )
}.distinctUntilChanged().filterNot { it.isWifiConnected && it.wifiName == null }.debounce(500L) }.distinctUntilChanged().filterNot { it.isWifiConnected && it.wifiName == null }.debounce(500L)
} }

View File

@ -30,13 +30,13 @@ class WifiService
constructor( constructor(
@ApplicationContext private val context: Context, @ApplicationContext private val context: Context,
private val settingsRepository: SettingsRepository, private val settingsRepository: SettingsRepository,
@AppShell private val rootShell: Provider<RootShell> @AppShell private val rootShell: Provider<RootShell>,
) : NetworkService { ) : NetworkService {
val mutex = Mutex() val mutex = Mutex()
private var ssid : String? = null private var ssid: String? = null
private var available : Boolean = false private var available: Boolean = false
private val connectivityManager = private val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
@ -105,12 +105,12 @@ constructor(
Timber.e(it) Timber.e(it)
emit(NetworkStatus.Unavailable()) emit(NetworkStatus.Unavailable())
}.transform { }.transform {
when(it) { when (it) {
is NetworkStatus.Available -> mutex.withLock { is NetworkStatus.Available -> mutex.withLock {
available = true available = true
} }
is NetworkStatus.CapabilitiesChanged -> mutex.withLock { is NetworkStatus.CapabilitiesChanged -> mutex.withLock {
if(available) { if (available) {
available = false available = false
Timber.d("Getting SSID from capabilities") Timber.d("Getting SSID from capabilities")
ssid = getNetworkName(it.networkCapabilities) ssid = getNetworkName(it.networkCapabilities)
@ -122,7 +122,7 @@ constructor(
} }
private suspend fun getNetworkName(networkCapabilities: NetworkCapabilities): String? { private suspend fun getNetworkName(networkCapabilities: NetworkCapabilities): String? {
if(settingsRepository.getSettings().isWifiNameByShellEnabled) return rootShell.get().getCurrentWifiName() if (settingsRepository.getSettings().isWifiNameByShellEnabled) return rootShell.get().getCurrentWifiName()
var ssid = networkCapabilities.getWifiName() var ssid = networkCapabilities.getWifiName()
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S) { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S) {
val wifiManager = val wifiManager =

View File

@ -0,0 +1,72 @@
package com.zaneschepke.wireguardautotunnel.service.shortcut
import android.content.Context
import android.content.Intent
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
import com.zaneschepke.wireguardautotunnel.R
class DynamicShortcutManager(private val context: Context) : ShortcutManager {
override fun addShortcuts() {
ShortcutManagerCompat.setDynamicShortcuts(context, createShortcuts())
}
override fun removeShortcuts() {
ShortcutManagerCompat.removeDynamicShortcuts(context, createShortcuts().map { it.id })
}
private fun createShortcuts(): List<ShortcutInfoCompat> {
return listOf(
buildShortcut(
context.getString(R.string.vpn_off),
context.getString(R.string.vpn_off),
context.getString(R.string.vpn_off),
intent = Intent(context, ShortcutsActivity::class.java).apply {
putExtra("className", "WireGuardTunnelService")
action = ShortcutsActivity.Action.STOP.name
},
shortcutIcon = R.drawable.vpn_off,
),
buildShortcut(
context.getString(R.string.vpn_on),
context.getString(R.string.vpn_on),
context.getString(R.string.vpn_on),
intent = Intent(context, ShortcutsActivity::class.java).apply {
putExtra("className", "WireGuardTunnelService")
action = ShortcutsActivity.Action.START.name
},
shortcutIcon = R.drawable.vpn_on,
),
buildShortcut(
context.getString(R.string.start_auto),
context.getString(R.string.start_auto),
context.getString(R.string.start_auto),
intent = Intent(context, ShortcutsActivity::class.java).apply {
putExtra("className", "WireGuardConnectivityWatcherService")
action = ShortcutsActivity.Action.START.name
},
shortcutIcon = R.drawable.auto_play,
),
buildShortcut(
context.getString(R.string.stop_auto),
context.getString(R.string.stop_auto),
context.getString(R.string.stop_auto),
intent = Intent(context, ShortcutsActivity::class.java).apply {
putExtra("className", "WireGuardConnectivityWatcherService")
action = ShortcutsActivity.Action.STOP.name
},
shortcutIcon = R.drawable.auto_pause,
),
)
}
private fun buildShortcut(id: String, shortLabel: String, longLabel: String, intent: Intent, shortcutIcon: Int): ShortcutInfoCompat {
return ShortcutInfoCompat.Builder(context, id)
.setShortLabel(shortLabel)
.setLongLabel(longLabel)
.setIntent(intent)
.setIcon(IconCompat.createWithResource(context, shortcutIcon))
.build()
}
}

View File

@ -0,0 +1,6 @@
package com.zaneschepke.wireguardautotunnel.service.shortcut
interface ShortcutManager {
fun addShortcuts()
fun removeShortcuts()
}

View File

@ -40,6 +40,7 @@ import androidx.navigation.compose.rememberNavController
import androidx.navigation.toRoute import androidx.navigation.toRoute
import com.zaneschepke.wireguardautotunnel.R import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.data.repository.AppStateRepository import com.zaneschepke.wireguardautotunnel.data.repository.AppStateRepository
import com.zaneschepke.wireguardautotunnel.service.shortcut.ShortcutManager
import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService
import com.zaneschepke.wireguardautotunnel.ui.common.navigation.BottomNavBar import com.zaneschepke.wireguardautotunnel.ui.common.navigation.BottomNavBar
import com.zaneschepke.wireguardautotunnel.ui.common.navigation.BottomNavItem import com.zaneschepke.wireguardautotunnel.ui.common.navigation.BottomNavItem
@ -78,6 +79,9 @@ class MainActivity : AppCompatActivity() {
@Inject @Inject
lateinit var tunnelService: TunnelService lateinit var tunnelService: TunnelService
@Inject
lateinit var shortcutManager: ShortcutManager
@OptIn(ExperimentalLayoutApi::class) @OptIn(ExperimentalLayoutApi::class)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge( enableEdgeToEdge(
@ -119,6 +123,10 @@ class MainActivity : AppCompatActivity() {
LaunchedEffect(isAutoTunnelEnabled) { LaunchedEffect(isAutoTunnelEnabled) {
this@MainActivity.requestAutoTunnelTileServiceUpdate() this@MainActivity.requestAutoTunnelTileServiceUpdate()
} }
LaunchedEffect(isShortcutsEnabled) {
if (!isShortcutsEnabled) return@LaunchedEffect shortcutManager.removeShortcuts()
shortcutManager.addShortcuts()
}
} }
CompositionLocalProvider(LocalNavController provides navController) { CompositionLocalProvider(LocalNavController provides navController) {

View File

@ -1,68 +0,0 @@
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<shortcut
android:enabled="true"
android:icon="@drawable/vpn_on"
android:shortcutDisabledMessage="@string/vpn_on"
android:shortcutId="defaultOn1"
android:shortcutLongLabel="@string/vpn_on"
android:shortcutShortLabel="@string/vpn_on">
<intent
android:action="START"
android:targetClass="com.zaneschepke.wireguardautotunnel.service.shortcut.ShortcutsActivity"
android:targetPackage="com.zaneschepke.wireguardautotunnel">
<extra
android:name="className"
android:value="WireGuardTunnelService" />
</intent>
<capability-binding android:key="actions.intent.START" />
</shortcut>
<shortcut
android:enabled="true"
android:icon="@drawable/vpn_off"
android:shortcutDisabledMessage="@string/vpn_off"
android:shortcutId="defaultOff1"
android:shortcutLongLabel="@string/vpn_off"
android:shortcutShortLabel="@string/vpn_off">
<intent
android:action="STOP"
android:targetClass="com.zaneschepke.wireguardautotunnel.service.shortcut.ShortcutsActivity"
android:targetPackage="com.zaneschepke.wireguardautotunnel">
<extra
android:name="className"
android:value="WireGuardTunnelService" />
</intent>
<capability-binding android:key="actions.intent.STOP" />
</shortcut>
<shortcut
android:enabled="true"
android:icon="@drawable/auto_play"
android:shortcutId="autoOn1"
android:shortcutLongLabel="@string/start_auto"
android:shortcutShortLabel="@string/start_auto">
<intent
android:action="START"
android:targetClass="com.zaneschepke.wireguardautotunnel.service.shortcut.ShortcutsActivity"
android:targetPackage="com.zaneschepke.wireguardautotunnel">
<extra
android:name="className"
android:value="WireGuardConnectivityWatcherService" />
</intent>
<capability-binding android:key="actions.intent.STOP" />
</shortcut>
<shortcut
android:enabled="true"
android:icon="@drawable/auto_pause"
android:shortcutId="autoOff1"
android:shortcutLongLabel="@string/stop_auto"
android:shortcutShortLabel="@string/stop_auto">
<intent
android:action="STOP"
android:targetClass="com.zaneschepke.wireguardautotunnel.service.shortcut.ShortcutsActivity"
android:targetPackage="com.zaneschepke.wireguardautotunnel">
<extra
android:name="className"
android:value="WireGuardConnectivityWatcherService" />
</intent>
<capability-binding android:key="actions.intent.STOP" />
</shortcut>
</shortcuts>