Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ app/release
local.properties
.vscode/launch.json
build/reports/problems/problems-report.html
.agents/
.agents/
7 changes: 2 additions & 5 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
<service
android:name=".service.MediaNotificationListener"
android:exported="false"
android:directBootAware="true"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
Expand Down Expand Up @@ -178,15 +179,11 @@



<!-- Wake-up Service for receiving reconnection requests from Mac -->
<service
android:name=".service.WakeupService"
android:exported="false" />

<!-- AirSync Service - maintains connection to Mac and handles call monitoring -->
<service
android:name=".service.AirSyncService"
android:exported="false"
android:directBootAware="true"
android:foregroundServiceType="connectedDevice" />

<service
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class AirSyncViewModel(
) : ViewModel() {

companion object {
private const val TAG = "AirSyncViewModel"
fun create(context: Context): AirSyncViewModel {
val dataStoreManager = DataStoreManager(context)
val repository = AirSyncRepositoryImpl(dataStoreManager)
Expand Down Expand Up @@ -129,6 +130,13 @@ class AirSyncViewModel(
}

init {
// Clear manual disconnect flag on app startup so auto-reconnect works
viewModelScope.launch {
try {
repository.setUserManuallyDisconnected(false)
} catch (_: Exception) {}
}

// Register for WebSocket connection status updates
WebSocketUtil.registerConnectionStatusListener(connectionStatusListener)
try {
Expand Down Expand Up @@ -219,6 +227,9 @@ class AirSyncViewModel(
appContext?.unregisterReceiver(powerSaveReceiver)
} catch (_: IllegalArgumentException) {
// Receiver was not registered
} catch (e: Exception) {
// Context may be invalid (Activity leaked)
Log.e(TAG, "Failed to unregister receiver: ${e.message}")
}
}

Expand Down Expand Up @@ -749,7 +760,7 @@ class AirSyncViewModel(
fun startNetworkMonitoring(context: Context) {
if (isNetworkMonitoringActive) return
isNetworkMonitoringActive = true
previousNetworkIp = DeviceInfoUtil.getWifiIpAddress(context) ?: "Unknown"
previousNetworkIp = DeviceInfoUtil.getWifiIpAddress(context) ?: DeviceInfoUtil.getLocalIpAddress() ?: "Unknown"

viewModelScope.launch {
try {
Expand Down Expand Up @@ -780,7 +791,7 @@ class AirSyncViewModel(
if (currentIp == "No Wi-Fi" || currentIp == "Unknown") {
// No usable Wi‑Fi: ensure we stop any active connection and do not attempt reconnect
try {
WebSocketUtil.disconnect(context)
WebSocketUtil.disconnect(context, isManual = false)
} catch (_: Exception) {
}
// Stop service if needed
Expand All @@ -803,7 +814,7 @@ class AirSyncViewModel(
// If connected/connecting to old network, disconnect first to force a clean switch
if (WebSocketUtil.isConnected() || WebSocketUtil.isConnecting()) {
try {
WebSocketUtil.disconnect(context)
WebSocketUtil.disconnect(context, isManual = false)
} catch (_: Exception) {
}
}
Expand Down Expand Up @@ -862,7 +873,7 @@ class AirSyncViewModel(
// No mapping for this network: disconnect if connected and, if allowed, start generic auto-reconnect
if (WebSocketUtil.isConnected() || WebSocketUtil.isConnecting()) {
try {
WebSocketUtil.disconnect(context)
WebSocketUtil.disconnect(context, isManual = false)
} catch (_: Exception) {
}
}
Expand Down
Loading