Skip to content

Commit

Permalink
Support UI control via Item
Browse files Browse the repository at this point in the history
Closes openhab#3540

Signed-off-by: mueller-ma <[email protected]>
  • Loading branch information
mueller-ma committed Jan 24, 2024
1 parent ccc8149 commit 50935de
Showing 1 changed file with 87 additions and 0 deletions.
87 changes: 87 additions & 0 deletions mobile/src/main/java/org/openhab/habdroid/ui/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package org.openhab.habdroid.ui

import android.Manifest
import android.app.Dialog
import android.app.PendingIntent
import android.content.ActivityNotFoundException
import android.content.ComponentName
Expand Down Expand Up @@ -61,19 +62,24 @@ import androidx.core.view.isVisible
import androidx.core.widget.ContentLoadingProgressBar
import androidx.drawerlayout.widget.DrawerLayout
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.navigation.NavigationView
import com.google.android.material.snackbar.Snackbar
import de.duenndns.ssl.MemorizingTrustManager
import java.nio.charset.Charset
import java.util.concurrent.CancellationException
import javax.jmdns.ServiceInfo
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.json.JSONException
import org.json.JSONObject
import org.openhab.habdroid.BuildConfig
import org.openhab.habdroid.R
import org.openhab.habdroid.background.BackgroundTasksManager
Expand Down Expand Up @@ -169,6 +175,9 @@ class MainActivity : AbstractBaseActivity(), ConnectionFactory.UpdateListener {
private var inServerSelectionMode = false
private var wifiSsidDuringLastOnStart: String? = null

private var uiCommandItemJob: Job? = null
private var uiCommandItemNotification: Dialog? = null

private val permissionRequestNoActionCallback =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {}

Expand Down Expand Up @@ -1129,6 +1138,7 @@ class MainActivity : AbstractBaseActivity(), ConnectionFactory.UpdateListener {
if (action != null && executeActionIfPossible(action)) {
pendingAction = null
}
setupUiCommandItem()
}

private fun executeActionIfPossible(action: PendingAction): Boolean = when {
Expand Down Expand Up @@ -1431,6 +1441,83 @@ class MainActivity : AbstractBaseActivity(), ConnectionFactory.UpdateListener {
}
}

private fun setupUiCommandItem () {
uiCommandItemJob?.cancel()
uiCommandItemJob = launch {
listenUiCommandItem()
}
}

private suspend fun listenUiCommandItem() {
val connection = connection ?: return
val eventSubscription = connection.httpClient.makeSse(
// Support for both the "openhab" and the older "smarthome" root topic by using a wildcard
// TODO: Limit to item
connection.httpClient.buildUrl("rest/events?topics=*/items/Command/command")
)

try {
while (isActive) {
try {
val event = JSONObject(eventSubscription.getNextEvent())
if (event.optString("type") == "ALIVE") {
Log.d(TAG, "Got ALIVE event")
continue
}
val topic = event.getString("topic")
val topicPath = topic.split('/')
// Possible formats:
// - openhab/items/<item>/statechanged
// - openhab/items/<group item>/<item>/statechanged
// When an update for a group is sent, there's also one for the individual item.
// Therefore always take the element on index two.
if (topicPath.size !in 4..5) {
throw JSONException("Unexpected topic path $topic")
}
val state = JSONObject(event.getString("payload")).getString("value")
Log.e(TAG, "Got state by event: $state")
handleUiCommand(state)
} catch (e: JSONException) {
Log.e(TAG, "Failed parsing JSON of state change event", e)
}
}
} finally {
eventSubscription.cancel()
}
}

private fun handleUiCommand(command: String) {
val prefix = command.substringBefore(":")
val commandContent = command.removePrefix("$prefix:")
when (prefix) {
"notification" -> {
val split = commandContent.split(":")
val message = "${split.getOrNull(0).orEmpty()}\n" +
"${split.getOrNull(2).orEmpty()}\n" +
split.getOrNull(3).orEmpty()
val closeAfter = split.getOrNull(4)?.toIntOrNull()
uiCommandItemNotification?.dismiss()
uiCommandItemNotification = MaterialAlertDialogBuilder(this)
.setTitle(split.getOrNull(1).orEmpty())
.setMessage(message)
.setPositiveButton(android.R.string.ok, null)
.show()
closeAfter?.let {
launch {
delay(closeAfter.milliseconds)
uiCommandItemNotification?.dismiss()
}
}
}
"close" -> uiCommandItemNotification?.dismiss()
"back" -> onBackPressedCallback.handleOnBackPressed()
"reload" -> recreate()
else -> {
Log.d(TAG, "Command not implemented: $command")
}
}
}

private fun manageHabPanelShortcut(visible: Boolean) {
manageShortcut(visible, "habpanel", ACTION_HABPANEL_SELECTED,
R.string.mainmenu_openhab_habpanel, R.mipmap.ic_shortcut_habpanel,
Expand Down

0 comments on commit 50935de

Please sign in to comment.