mirror of
https://github.com/home-assistant/android
synced 2024-07-22 10:54:12 +00:00
Update Thread network sync to update/delete HA networks (#3676)
This commit is contained in:
parent
ef916f606b
commit
7b79024c1b
|
@ -76,14 +76,41 @@ class ThreadManagerImpl @Inject constructor(
|
|||
try {
|
||||
val coreIsDevicePreferred = isPreferredDatasetByDevice(context, coreThreadDataset.datasetId, serverId)
|
||||
Log.d(TAG, "Thread: device ${if (coreIsDevicePreferred) "prefers" else "doesn't prefer" } core preferred dataset")
|
||||
val appIsDevicePreferred = coreIsDevicePreferred || appAddedIsPreferredCredentials(context)
|
||||
Log.d(TAG, "Thread: device ${if (appIsDevicePreferred) "prefers" else "doesn't prefer" } dataset from app")
|
||||
|
||||
var exportFromDevice = false
|
||||
var updated: Boolean? = null
|
||||
if (!coreIsDevicePreferred) {
|
||||
if (appIsDevicePreferred) {
|
||||
// Update or remove the device preferred credential to match core state
|
||||
try {
|
||||
updated = if (coreThreadDataset.source != "Google") { // Credential from HA, update
|
||||
importDatasetFromServer(context, coreThreadDataset.datasetId, serverId)
|
||||
true
|
||||
} else { // Imported from another app, so this shouldn't be managed by HA
|
||||
deleteThreadCredential(context)
|
||||
false
|
||||
}
|
||||
Log.d(TAG, "Thread update device completed")
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Thread update device failed", e)
|
||||
}
|
||||
} else {
|
||||
exportFromDevice = true
|
||||
}
|
||||
}
|
||||
|
||||
// Import the dataset to core if different from device
|
||||
ThreadManager.SyncResult.AllHaveCredentials(
|
||||
matches = coreIsDevicePreferred,
|
||||
exportIntent = if (coreIsDevicePreferred) null else deviceThreadIntent
|
||||
fromApp = appIsDevicePreferred,
|
||||
updated = updated,
|
||||
exportIntent = if (exportFromDevice) deviceThreadIntent else null
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Thread device/core preferred comparison failed", e)
|
||||
ThreadManager.SyncResult.AllHaveCredentials(matches = null, exportIntent = null)
|
||||
ThreadManager.SyncResult.AllHaveCredentials(matches = null, fromApp = null, updated = null, exportIntent = null)
|
||||
}
|
||||
} else {
|
||||
ThreadManager.SyncResult.NoneHaveCredentials
|
||||
|
@ -119,16 +146,34 @@ class ThreadManagerImpl @Inject constructor(
|
|||
|
||||
private suspend fun isPreferredDatasetByDevice(context: Context, datasetId: String, serverId: Int): Boolean {
|
||||
val tlv = serverManager.webSocketRepository(serverId).getThreadDatasetTlv(datasetId)?.tlvAsByteArray
|
||||
if (tlv != null) {
|
||||
return if (tlv != null) {
|
||||
val threadNetworkCredentials = ThreadNetworkCredentials.fromActiveOperationalDataset(tlv)
|
||||
return suspendCoroutine { cont ->
|
||||
ThreadNetwork.getClient(context)
|
||||
.isPreferredCredentials(threadNetworkCredentials)
|
||||
.addOnSuccessListener { cont.resume(it == IsPreferredCredentialsResult.PREFERRED_CREDENTIALS_MATCHED) }
|
||||
.addOnFailureListener { cont.resumeWithException(it) }
|
||||
}
|
||||
isPreferredCredentials(context, threadNetworkCredentials)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private suspend fun appAddedIsPreferredCredentials(context: Context): Boolean {
|
||||
val appCredentials = suspendCoroutine { cont ->
|
||||
ThreadNetwork.getClient(context)
|
||||
.allCredentials
|
||||
.addOnSuccessListener { cont.resume(it) }
|
||||
.addOnFailureListener { cont.resume(null) }
|
||||
}
|
||||
return try {
|
||||
appCredentials?.any { isPreferredCredentials(context, it) } ?: false
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Thread app added credentials preferred check failed", e)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun isPreferredCredentials(context: Context, credentials: ThreadNetworkCredentials): Boolean = suspendCoroutine { cont ->
|
||||
ThreadNetwork.getClient(context)
|
||||
.isPreferredCredentials(credentials)
|
||||
.addOnSuccessListener { cont.resume(it == IsPreferredCredentialsResult.PREFERRED_CREDENTIALS_MATCHED) }
|
||||
.addOnFailureListener { cont.resumeWithException(it) }
|
||||
}
|
||||
|
||||
override suspend fun sendThreadDatasetExportResult(result: ActivityResult, serverId: Int): String? {
|
||||
|
@ -143,4 +188,13 @@ class ThreadManagerImpl @Inject constructor(
|
|||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private suspend fun deleteThreadCredential(context: Context) = suspendCoroutine { cont ->
|
||||
// This only works because we currently always use the same border agent ID
|
||||
val threadBorderAgent = ThreadBorderAgent.newBuilder(BORDER_AGENT_ID.toByteArray()).build()
|
||||
ThreadNetwork.getClient(context)
|
||||
.removeCredentials(threadBorderAgent)
|
||||
.addOnSuccessListener { cont.resume(true) }
|
||||
.addOnFailureListener { cont.resumeWithException(it) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,6 +83,10 @@ class DeveloperSettingsPresenterImpl @Inject constructor(
|
|||
view.onThreadPermissionRequest(syncResult.exportIntent, serverId, false)
|
||||
} else if (syncResult.matches == true) {
|
||||
view.onThreadDebugResult(context.getString(commonR.string.thread_debug_result_match), true)
|
||||
} else if (syncResult.fromApp == true && syncResult.updated == true) {
|
||||
view.onThreadDebugResult(context.getString(commonR.string.thread_debug_result_updated), true)
|
||||
} else if (syncResult.fromApp == true && syncResult.updated == false) {
|
||||
view.onThreadDebugResult(context.getString(commonR.string.thread_debug_result_removed), true)
|
||||
} else {
|
||||
view.onThreadDebugResult(context.getString(commonR.string.thread_debug_result_error), false)
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ interface ThreadManager {
|
|||
object ServerUnsupported : SyncResult()
|
||||
class OnlyOnServer(val imported: Boolean) : SyncResult()
|
||||
class OnlyOnDevice(val exportIntent: IntentSender?) : SyncResult()
|
||||
class AllHaveCredentials(val matches: Boolean?, val exportIntent: IntentSender?) : SyncResult()
|
||||
class AllHaveCredentials(val matches: Boolean?, val fromApp: Boolean?, val updated: Boolean?, val exportIntent: IntentSender?) : SyncResult()
|
||||
object NoneHaveCredentials : SyncResult()
|
||||
}
|
||||
|
||||
|
|
|
@ -1084,7 +1084,9 @@
|
|||
<string name="thread_debug_result_mismatch">Home Assistant and this device prefer different networks</string>
|
||||
<string name="thread_debug_result_mismatch_detail">(device prefers: %1$s)</string>
|
||||
<string name="thread_debug_result_none">No credentials to sync</string>
|
||||
<string name="thread_debug_result_removed">Removed old network from Home Assistant on this device</string>
|
||||
<string name="thread_debug_result_unsupported_server">The Home Assistant server does not support Thread</string>
|
||||
<string name="thread_debug_result_updated">Updated network from Home Assistant on this device</string>
|
||||
<string name="thread_debug_summary">Manually update device and server Thread credentials and verify results</string>
|
||||
<string name="tile_vibrate">Vibrate when clicked</string>
|
||||
<string name="tile_auth_required">Requires unlocked device</string>
|
||||
|
|
Loading…
Reference in a new issue