diff --git a/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl b/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl index 4914c024..d303b025 100644 --- a/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl +++ b/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl @@ -95,6 +95,12 @@ interface IMeshService { /// It sets a ChannelSet protobuf void setChannels(in byte []payload); + /// Send Shutdown admin packet to nodeNum + void requestShutdown(in String nodeId); + + /// Send Reboot admin packet to nodeNum + void requestReboot(in String nodeId); + /** Is the packet radio currently connected to the phone? Returns a ConnectionState string. */ diff --git a/app/src/main/java/com/geeksville/mesh/model/UIState.kt b/app/src/main/java/com/geeksville/mesh/model/UIState.kt index 7d46a6f8..ec3641f2 100644 --- a/app/src/main/java/com/geeksville/mesh/model/UIState.kt +++ b/app/src/main/java/com/geeksville/mesh/model/UIState.kt @@ -279,6 +279,14 @@ class UIViewModel @Inject constructor( } } + fun requestShutdown() { + meshService?.requestShutdown(DataPacket.ID_LOCAL) + } + + fun requestReboot() { + meshService?.requestReboot(DataPacket.ID_LOCAL) + } + /** * Write the persisted packet data out to a CSV file in the specified location. */ diff --git a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt index ac7c7b75..5bf23041 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt @@ -1406,6 +1406,18 @@ class MeshService : Service(), Logging { }) } + private fun requestShutdown(nodeId: String) { + sendToRadio(newMeshPacketTo(toNodeNum(nodeId)).buildAdminPacket { + shutdownSeconds = 5 + }) + } + + private fun requestReboot(nodeId: String) { + sendToRadio(newMeshPacketTo(toNodeNum(nodeId)).buildAdminPacket { + rebootSeconds = 5 + }) + } + /** * Start the modern (REV2) API configuration flow */ @@ -1763,6 +1775,14 @@ class MeshService : Service(), Logging { override fun stopProvideLocation() = toRemoteExceptions { stopLocationRequests() } + + override fun requestShutdown(nodeId: String) = toRemoteExceptions { + this@MeshService.requestShutdown(nodeId) + } + + override fun requestReboot(nodeId: String) = toRemoteExceptions { + this@MeshService.requestReboot(nodeId) + } } } diff --git a/app/src/main/java/com/geeksville/mesh/ui/AdvancedSettingsFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/AdvancedSettingsFragment.kt index 05c32525..5f86ef62 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/AdvancedSettingsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/AdvancedSettingsFragment.kt @@ -14,6 +14,7 @@ import com.geeksville.mesh.model.ChannelOption import com.geeksville.mesh.model.UIViewModel import com.geeksville.mesh.service.MeshService import com.geeksville.util.exceptionToSnackbar +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint @@ -52,6 +53,8 @@ class AdvancedSettingsFragment : ScreenFragment("Advanced Settings"), Logging { binding.lsSleepView.isEnabled = connected && model.isPowerSaving ?: false binding.positionBroadcastSwitch.isEnabled = connected binding.lsSleepSwitch.isEnabled = connected + binding.shutdownButton.isEnabled = connected + binding.rebootButton.isEnabled = connected } binding.positionBroadcastPeriodEditText.on(EditorInfo.IME_ACTION_DONE) { @@ -106,5 +109,27 @@ class AdvancedSettingsFragment : ScreenFragment("Advanced Settings"), Logging { debug("User changed isPowerSaving to $isChecked") } } + + binding.shutdownButton.setOnClickListener { + MaterialAlertDialogBuilder(requireContext()) + .setMessage("${getString(R.string.update_firmware)}?") + .setNeutralButton(R.string.cancel) { _, _ -> + } + .setPositiveButton(getString(R.string.okay)) { _, _ -> + model.requestShutdown() + } + .show() + } + + binding.rebootButton.setOnClickListener { + MaterialAlertDialogBuilder(requireContext()) + .setMessage("${getString(R.string.update_firmware)}?") + .setNeutralButton(R.string.cancel) { _, _ -> + } + .setPositiveButton(getString(R.string.okay)) { _, _ -> + model.requestReboot() + } + .show() + } } } \ No newline at end of file diff --git a/app/src/main/res/layout/advanced_settings.xml b/app/src/main/res/layout/advanced_settings.xml index 79f1dfe8..5d22f6a5 100644 --- a/app/src/main/res/layout/advanced_settings.xml +++ b/app/src/main/res/layout/advanced_settings.xml @@ -65,4 +65,27 @@ app:layout_constraintBottom_toBottomOf="@id/lsSleepView" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="@id/lsSleepView" /> + + + + \ No newline at end of file