Modify wildcardFragment for multiple attribute,event (#25677)
diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt
index a9861aa..70d1849 100644
--- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt
+++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt
@@ -11,6 +11,7 @@
import android.widget.EditText
import android.widget.Spinner
import android.widget.TextView
+import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import chip.devicecontroller.ChipDeviceController
@@ -28,6 +29,7 @@
import chip.devicecontroller.model.NodeState
import chip.tlv.AnonymousTag
import chip.tlv.ContextSpecificTag
+import chip.tlv.TlvReader
import chip.tlv.TlvWriter
import com.google.chip.chiptool.ChipClient
import com.google.chip.chiptool.R
@@ -37,6 +39,8 @@
import java.util.Optional
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
+import kotlin.coroutines.resume
+import kotlin.coroutines.suspendCoroutine
class WildcardFragment : Fragment() {
private var _binding: WildcardFragmentBinding? = null
@@ -49,6 +53,10 @@
private lateinit var addressUpdateFragment: AddressUpdateFragment
+ private val attributePath = ArrayList<ChipAttributePath>()
+ private val eventPath = ArrayList<ChipEventPath>()
+ private val subscribeIdList = ArrayList<ULong>()
+
private val reportCallback = object : ReportCallback {
override fun onError(attributePath: ChipAttributePath?, eventPath: ChipEventPath?, ex: Exception) {
if (attributePath != null)
@@ -108,12 +116,42 @@
): View {
_binding = WildcardFragmentBinding.inflate(inflater, container, false)
scope = viewLifecycleOwner.lifecycleScope
- binding.subscribeBtn.setOnClickListener { scope.launch { showSubscribeDialog(ATTRIBUTE) } }
- binding.readBtn.setOnClickListener { scope.launch { showReadDialog(ATTRIBUTE) } }
- binding.writeBtn.setOnClickListener { scope.launch { showWriteDialog() } }
- binding.subscribeEventBtn.setOnClickListener { scope.launch { showSubscribeDialog(EVENT) } }
- binding.readEventBtn.setOnClickListener { scope.launch { showReadDialog(EVENT) } }
- binding.invokeBtn.setOnClickListener { scope.launch { showInvokeDialog() } }
+
+ binding.selectTypeRadioGroup.setOnCheckedChangeListener { _, i ->
+ val readBtnOn = (i == R.id.readRadioBtn)
+ val subscribeBtnOn = (i == R.id.subscribeRadioBtn)
+ val writeBtnOn = (i == R.id.writeRadioBtn)
+ val invokeBtnOn = (i == R.id.invokeRadioBtn)
+
+ binding.addLayout.visibility = getVisibility(readBtnOn || subscribeBtnOn)
+ binding.attributeIdLabel.visibility = getVisibility(readBtnOn || subscribeBtnOn || writeBtnOn)
+ binding.attributeIdEd.visibility = getVisibility(readBtnOn || subscribeBtnOn || writeBtnOn)
+ binding.eventIdLabel.visibility = getVisibility(readBtnOn || subscribeBtnOn)
+ binding.eventIdEd.visibility = getVisibility(readBtnOn || subscribeBtnOn)
+ binding.commandIdLabel.visibility = getVisibility(invokeBtnOn)
+ binding.commandIdEd.visibility = getVisibility(invokeBtnOn)
+ binding.isUrgentLabel.visibility = getVisibility(subscribeBtnOn)
+ binding.isUrgentSp.visibility = getVisibility(subscribeBtnOn)
+ binding.shutdownSubscriptionBtn.visibility = getVisibility(subscribeBtnOn)
+ }
+
+ binding.sendBtn.setOnClickListener {
+ if (binding.readRadioBtn.isChecked) {
+ showReadDialog()
+ } else if (binding.subscribeRadioBtn.isChecked) {
+ showSubscribeDialog()
+ } else if (binding.writeRadioBtn.isChecked) {
+ showWriteDialog()
+ } else if (binding.invokeRadioBtn.isChecked) {
+ showInvokeDialog()
+ }
+ }
+
+ binding.shutdownSubscriptionBtn.setOnClickListener { showShutdownSubscriptionDialog() }
+
+ binding.addAttributeBtn.setOnClickListener { addPathList(ATTRIBUTE) }
+ binding.addEventBtn.setOnClickListener { addPathList(EVENT) }
+ binding.resetBtn.setOnClickListener { resetPath() }
addressUpdateFragment =
childFragmentManager.findFragmentById(R.id.addressUpdateFragment) as AddressUpdateFragment
@@ -121,6 +159,43 @@
return binding.root
}
+ private fun getVisibility(isShowing: Boolean) : Int {
+ return if (isShowing) { View.VISIBLE } else { View.GONE }
+ }
+
+ private fun addPathList(type: Int) {
+ val endpointId = getChipPathIdForText(binding.endpointIdEd.text.toString())
+ val clusterId = getChipPathIdForText(binding.clusterIdEd.text.toString())
+ val attributeId = getChipPathIdForText(binding.attributeIdEd.text.toString())
+ val eventId = getChipPathIdForText(binding.eventIdEd.text.toString())
+ // Only Subscribe used
+ val isUrgent = (binding.subscribeRadioBtn.isChecked) && (binding.isUrgentSp.selectedItem.toString().toBoolean())
+
+ if (type == ATTRIBUTE) {
+ attributePath.add(ChipAttributePath.newInstance(endpointId, clusterId, attributeId))
+ } else if (type == EVENT) {
+ eventPath.add(ChipEventPath.newInstance(endpointId, clusterId, eventId, isUrgent))
+ }
+ updateAddListView()
+ }
+
+ private fun resetPath() {
+ attributePath.clear()
+ eventPath.clear()
+ updateAddListView()
+ }
+
+ private fun updateAddListView() {
+ val builder = StringBuilder()
+ for (attribute in attributePath) {
+ builder.append("attribute($attribute)\n")
+ }
+ for (event in eventPath) {
+ builder.append("event($event)\n")
+ }
+ binding.sendListView.text = builder.toString()
+ }
+
override fun onDestroyView() {
super.onDestroyView()
_binding = null
@@ -154,75 +229,43 @@
return stringBuilder.toString()
}
- private suspend fun subscribe(type: Int, minInterval: Int, maxInterval: Int, keepSubscriptions: Boolean, isFabricFiltered: Boolean, isUrgent: Boolean) {
+ private suspend fun subscribe(minInterval: Int, maxInterval: Int, keepSubscriptions: Boolean, isFabricFiltered: Boolean) {
val subscriptionEstablishedCallback =
- SubscriptionEstablishedCallback { Log.i(TAG, "Subscription to device established") }
+ SubscriptionEstablishedCallback {
+ subscriptionId ->
+ Log.i(TAG, "Subscription to device established : ${subscriptionId.toULong()}")
+ subscribeIdList.add(subscriptionId.toULong())
+ requireActivity().runOnUiThread {
+ Toast.makeText(requireActivity(), "${getString(R.string.wildcard_subscribe_established_toast_message)} : $subscriptionId", Toast.LENGTH_SHORT).show()
+ }
+ }
val resubscriptionAttemptCallback =
ResubscriptionAttemptCallback { terminationCause, nextResubscribeIntervalMsec
-> Log.i(TAG, "ResubscriptionAttempt terminationCause:$terminationCause, nextResubscribeIntervalMsec:$nextResubscribeIntervalMsec") }
- val endpointId = getChipPathIdForText(binding.endpointIdEd.text.toString())
- val clusterId = getChipPathIdForText(binding.clusterIdEd.text.toString())
- val attributeId = getChipPathIdForText(binding.attributeIdEd.text.toString())
- val eventId = getChipPathIdForText(binding.eventIdEd.text.toString())
-
- if (type == ATTRIBUTE) {
- val attributePath = ChipAttributePath.newInstance(endpointId, clusterId, attributeId)
- deviceController.subscribeToPath(subscriptionEstablishedCallback,
- resubscriptionAttemptCallback,
- reportCallback,
- ChipClient.getConnectedDevicePointer(requireContext(),
- addressUpdateFragment.deviceId),
- listOf(attributePath),
- null,
- minInterval,
- maxInterval,
- keepSubscriptions,
- isFabricFiltered,
- /* imTimeoutMs= */ 0)
- } else if (type == EVENT) {
- val eventPath = ChipEventPath.newInstance(endpointId, clusterId, eventId, isUrgent)
- deviceController.subscribeToPath(subscriptionEstablishedCallback,
- resubscriptionAttemptCallback,
- reportCallback,
- ChipClient.getConnectedDevicePointer(requireContext(),
- addressUpdateFragment.deviceId),
- null,
- listOf(eventPath),
- minInterval,
- maxInterval,
- keepSubscriptions,
- isFabricFiltered,
- /* imTimeoutMs= */ 0)
- }
+ deviceController.subscribeToPath(subscriptionEstablishedCallback,
+ resubscriptionAttemptCallback,
+ reportCallback,
+ ChipClient.getConnectedDevicePointer(requireContext(),
+ addressUpdateFragment.deviceId),
+ attributePath.ifEmpty { null },
+ eventPath.ifEmpty { null },
+ minInterval,
+ maxInterval,
+ keepSubscriptions,
+ isFabricFiltered,
+ /* imTimeoutMs= */ 0)
}
- private suspend fun read(type: Int, isFabricFiltered: Boolean) {
- val endpointId = getChipPathIdForText(binding.endpointIdEd.text.toString())
- val clusterId = getChipPathIdForText(binding.clusterIdEd.text.toString())
- val attributeId = getChipPathIdForText(binding.attributeIdEd.text.toString())
- val eventId = getChipPathIdForText(binding.eventIdEd.text.toString())
-
- if (type == ATTRIBUTE) {
- val attributePath = ChipAttributePath.newInstance(endpointId, clusterId, attributeId)
- deviceController.readPath(reportCallback,
- ChipClient.getConnectedDevicePointer(requireContext(),
- addressUpdateFragment.deviceId),
- listOf(attributePath),
- null,
- isFabricFiltered,
- /* imTimeoutMs= */ 0)
- } else if (type == EVENT) {
- val eventPath = ChipEventPath.newInstance(endpointId, clusterId, eventId)
- deviceController.readPath(reportCallback,
- ChipClient.getConnectedDevicePointer(requireContext(),
- addressUpdateFragment.deviceId),
- null,
- listOf(eventPath),
- isFabricFiltered,
- /* imTimeoutMs= */ 0)
- }
+ private suspend fun read(isFabricFiltered: Boolean) {
+ deviceController.readPath(reportCallback,
+ ChipClient.getConnectedDevicePointer(requireContext(),
+ addressUpdateFragment.deviceId),
+ attributePath.ifEmpty { null },
+ eventPath.ifEmpty { null },
+ isFabricFiltered,
+ /* imTimeoutMs= */ 0)
}
private suspend fun write(writeValueType: String, writeValue: String, dataVersion: Int?, timedRequestTimeoutMs: Int, imTimeoutMs: Int) {
@@ -285,7 +328,13 @@
imTimeoutMs)
}
- private fun showReadDialog(type: Int) {
+ private fun showReadDialog() {
+ if (attributePath.isEmpty() && eventPath.isEmpty()) {
+ requireActivity().runOnUiThread {
+ Toast.makeText(requireActivity(), R.string.wildcard_empty_error_toast_message, Toast.LENGTH_SHORT).show()
+ }
+ return
+ }
val dialogView = requireActivity().layoutInflater.inflate(R.layout.read_dialog, null)
val dialog = AlertDialog.Builder(requireContext()).apply {
setView(dialogView)
@@ -294,7 +343,7 @@
val isFabricFilteredEd = dialogView.findViewById<EditText>(R.id.isFabricFilteredSp)
dialogView.findViewById<Button>(R.id.readBtn).setOnClickListener {
scope.launch {
- read(type, isFabricFilteredEd.text.toString().toBoolean())
+ read(isFabricFilteredEd.text.toString().toBoolean())
requireActivity().runOnUiThread { dialog.dismiss() }
}
}
@@ -305,7 +354,7 @@
binding.outputTv.text = ""
val dialogView = requireActivity().layoutInflater.inflate(R.layout.write_dialog, null)
val writeValueTypeSp = dialogView.findViewById<Spinner>(R.id.writeValueTypeSp)
- val spinnerAdapter = ArrayAdapter(requireActivity(), android.R.layout.simple_spinner_item, TLV_MAP.keys.toList())
+ val spinnerAdapter = ArrayAdapter(requireActivity(), android.R.layout.simple_spinner_dropdown_item, TLV_MAP.keys.toList())
writeValueTypeSp.adapter = spinnerAdapter
val dialog = AlertDialog.Builder(requireContext()).apply {
setView(dialogView)
@@ -328,17 +377,14 @@
dialog.show()
}
- private fun showSubscribeDialog(type: Int) {
- val dialogView = requireActivity().layoutInflater.inflate(R.layout.subscribe_dialog, null)
- val isUrgentTv = dialogView.findViewById<TextView>(R.id.titleisUrgent)
- val isUrgentSp = dialogView.findViewById<Spinner>(R.id.isUrgentSp)
- if (type == EVENT) {
- isUrgentTv.visibility = View.VISIBLE
- isUrgentSp.visibility = View.VISIBLE
- } else {
- isUrgentTv.visibility = View.GONE
- isUrgentSp.visibility = View.GONE
+ private fun showSubscribeDialog() {
+ if (attributePath.isEmpty() && eventPath.isEmpty()) {
+ requireActivity().runOnUiThread {
+ Toast.makeText(requireActivity(), R.string.wildcard_empty_error_toast_message, Toast.LENGTH_SHORT).show()
+ }
+ return
}
+ val dialogView = requireActivity().layoutInflater.inflate(R.layout.subscribe_dialog, null)
val dialog = AlertDialog.Builder(requireContext()).apply {
setView(dialogView)
}.create()
@@ -351,12 +397,10 @@
scope.launch {
if(minIntervalEd.text.isNotBlank() && maxIntervalEd.text.isNotBlank()) {
subscribe(
- type,
minIntervalEd.text.toString().toInt(),
maxIntervalEd.text.toString().toInt(),
keepSubscriptionsSp.selectedItem.toString().toBoolean(),
isFabricFilteredSp.selectedItem.toString().toBoolean(),
- isUrgentSp.selectedItem.toString().toBoolean(),
)
} else {
Log.e(TAG, "minInterval or maxInterval is empty!" )
@@ -389,6 +433,87 @@
dialog.show()
}
+ private suspend fun readCurrentFabricIndex() : UInt {
+ val context = requireContext()
+ val endpointId = 0L
+ val clusterId = 62L // OperationalCredentials
+ val attributeId = 5L // CurrentFabricIndex
+ val deviceId = addressUpdateFragment.deviceId
+ val devicePointer = ChipClient.getConnectedDevicePointer(context, deviceId)
+ return suspendCoroutine { cont ->
+ deviceController.readAttributePath(object : ReportCallback {
+ override fun onError(attributePath: ChipAttributePath?, eventPath: ChipEventPath?, e: java.lang.Exception?) {
+ cont.resume(0u)
+ }
+
+ override fun onReport(nodeState: NodeState?) {
+ val state = nodeState?.getEndpointState(endpointId.toInt())?.
+ getClusterState(clusterId)?.
+ getAttributeState(attributeId)
+ if (state == null) {
+ cont.resume(0u)
+ return
+ }
+ val ret = TlvReader(state.tlv).getUInt(AnonymousTag)
+ cont.resume(ret)
+ }
+ }, devicePointer,
+ listOf(ChipAttributePath.newInstance(endpointId, clusterId, attributeId)),
+ 0 /* imTimeoutMs */
+ )
+ }
+ }
+
+ private fun shutdownSubscription(fabricIndex: UInt, subscribeId: ULong? = null) {
+ val deviceId = addressUpdateFragment.deviceId
+ if (subscribeId != null) {
+ deviceController.shutdownSubscriptions(fabricIndex.toInt(), deviceId, subscribeId.toLong())
+ subscribeIdList.remove(subscribeId)
+ } else {
+ deviceController.shutdownSubscriptions(fabricIndex.toInt(), deviceId)
+ }
+ }
+
+ private fun showShutdownSubscriptionDialog() {
+ val dialogView = requireActivity().layoutInflater.inflate(R.layout.shutdown_subscribe_dialog, null)
+ val subscriptionIdSp = dialogView.findViewById<Spinner>(R.id.subscribeIdSp)
+ val fabricIndexTv = dialogView.findViewById<TextView>(R.id.fabricIndexValue)
+ val shutdownBtn = dialogView.findViewById<Button>(R.id.shutdownBtn)
+ val shutdownAllBtn = dialogView.findViewById<Button>(R.id.shutdownAllBtn)
+ val spinnerAdapter = ArrayAdapter(requireActivity(), android.R.layout.simple_spinner_dropdown_item, subscribeIdList)
+ subscriptionIdSp.adapter = spinnerAdapter
+ val dialog = AlertDialog.Builder(requireContext()).apply {
+ setView(dialogView)
+ }.create()
+
+ shutdownBtn.setOnClickListener {
+ val fabricIndex = fabricIndexTv.text.toString().toUInt()
+ val subscribeId = subscriptionIdSp.selectedItem.toString().toULong()
+ scope.launch {
+ shutdownSubscription(fabricIndex, subscribeId)
+ requireActivity().runOnUiThread { dialog.dismiss() }
+ }
+ }
+
+ shutdownAllBtn.setOnClickListener {
+ scope.launch {
+ val fabricIndex = fabricIndexTv.text.toString().toUInt()
+ shutdownSubscription(fabricIndex)
+ requireActivity().runOnUiThread { dialog.dismiss() }
+ }
+ }
+ dialog.show()
+
+ scope.launch {
+ val fabricIndex = readCurrentFabricIndex()
+ requireActivity().runOnUiThread {
+ fabricIndexTv.text = fabricIndex.toString()
+ shutdownBtn.isEnabled = true
+ shutdownAllBtn.isEnabled = true
+ }
+ }
+ }
+
private fun getChipPathIdForText(text: String): ChipPathId {
return if (text.isEmpty()) ChipPathId.forWildcard() else ChipPathId.forId(text.toLong())
}
diff --git a/examples/android/CHIPTool/app/src/main/res/layout/read_dialog.xml b/examples/android/CHIPTool/app/src/main/res/layout/read_dialog.xml
index 0713df0..4ac2a1c 100644
--- a/examples/android/CHIPTool/app/src/main/res/layout/read_dialog.xml
+++ b/examples/android/CHIPTool/app/src/main/res/layout/read_dialog.xml
@@ -22,8 +22,8 @@
android:textSize="16sp"
android:layout_marginBottom="8dp"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/isFabricFilteredSp"
- app:layout_constraintBottom_toTopOf="@+id/subscribeBtn"/>
+ app:layout_constraintTop_toBottomOf="@id/titleText"
+ app:layout_constraintBottom_toTopOf="@+id/readBtn"/>
<Button
android:id="@+id/readBtn"
diff --git a/examples/android/CHIPTool/app/src/main/res/layout/shutdown_subscribe_dialog.xml b/examples/android/CHIPTool/app/src/main/res/layout/shutdown_subscribe_dialog.xml
new file mode 100644
index 0000000..28d0b32
--- /dev/null
+++ b/examples/android/CHIPTool/app/src/main/res/layout/shutdown_subscribe_dialog.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="16dp">
+ <TextView
+ android:id="@+id/titleText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/shutdown_dialog_title_text"
+ android:textSize="22sp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/titleFabricIndex"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/shutdown_dialog_fabric_index_hint"
+ android:textSize="16sp"
+ android:layout_marginTop="8dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/titleText"
+ />
+
+ <TextView
+ android:id="@+id/fabricIndexValue"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textSize="16sp"
+ android:layout_marginTop="8dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/titleFabricIndex"
+ />
+
+ <TextView
+ android:id="@+id/titleSubscriptionId"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/shutdown_dialog_subscription_id_hint"
+ android:textSize="16sp"
+ android:layout_marginTop="8dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/fabricIndexValue"
+ />
+ <Spinner
+ android:id="@+id/subscribeIdSp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:hint="@string/shutdown_dialog_subscription_id_hint"
+ android:inputType="text"
+ android:spinnerMode="dropdown"
+ android:textSize="16sp"
+ android:layout_marginTop="8dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toTopOf="@+id/shutdownBtn"
+ app:layout_constraintTop_toBottomOf="@id/titleSubscriptionId" />
+
+ <Button
+ android:id="@+id/shutdownBtn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:enabled="false"
+ android:text="@string/shutdown_dialog_shutdown_btn_text"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/shutdownAllBtn"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <Button
+ android:id="@+id/shutdownAllBtn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:enabled="false"
+ android:text="@string/shutdown_dialog_shutdown_all_btn_text"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@id/shutdownBtn"
+ app:layout_constraintEnd_toEndOf="parent" />
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/examples/android/CHIPTool/app/src/main/res/layout/subscribe_dialog.xml b/examples/android/CHIPTool/app/src/main/res/layout/subscribe_dialog.xml
index a80d414..3830ddf 100644
--- a/examples/android/CHIPTool/app/src/main/res/layout/subscribe_dialog.xml
+++ b/examples/android/CHIPTool/app/src/main/res/layout/subscribe_dialog.xml
@@ -35,28 +35,6 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/minIntervalEd" />
<TextView
- android:id="@+id/titleisUrgent"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/subscribe_dialog_is_urgent_hint"
- android:textSize="16sp"
- android:layout_marginTop="8dp"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/maxIntervalEd"
- />
- <Spinner
- android:id="@+id/isUrgentSp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:hint="@string/subscribe_dialog_is_urgent_hint"
- android:entries="@array/chip_select_menu"
- android:inputType="text"
- android:spinnerMode="dropdown"
- android:textSize="16sp"
- android:layout_marginTop="8dp"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/titleisUrgent" />
- <TextView
android:id="@+id/titleKeepSubscriptions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -64,7 +42,7 @@
android:textSize="16sp"
android:layout_marginTop="8dp"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/isUrgentSp"
+ app:layout_constraintTop_toBottomOf="@id/maxIntervalEd"
/>
<Spinner
android:id="@+id/keepSubscriptionsSp"
diff --git a/examples/android/CHIPTool/app/src/main/res/layout/wildcard_fragment.xml b/examples/android/CHIPTool/app/src/main/res/layout/wildcard_fragment.xml
index cf68b2c..a6c7762 100644
--- a/examples/android/CHIPTool/app/src/main/res/layout/wildcard_fragment.xml
+++ b/examples/android/CHIPTool/app/src/main/res/layout/wildcard_fragment.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingStart="16dp"
@@ -15,12 +16,47 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
+ <RadioGroup
+ android:id="@+id/selectTypeRadioGroup"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/addressUpdateFragment">
+ <RadioButton
+ android:id="@+id/readRadioBtn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:checked="true"
+ android:textSize="16sp"
+ android:text="@string/wildcard_read_btn_text"/>
+ <RadioButton
+ android:id="@+id/subscribeRadioBtn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="16sp"
+ android:text="@string/wildcard_subscribe_btn_text"/>
+ <RadioButton
+ android:id="@+id/writeRadioBtn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="16sp"
+ android:text="@string/wildcard_write_btn_text"/>
+ <RadioButton
+ android:id="@+id/invokeRadioBtn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="16sp"
+ android:text="@string/wildcard_invoke_btn_text"/>
+ </RadioGroup>
+
<androidx.constraintlayout.helper.widget.Flow
android:id="@+id/flow"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
- app:constraint_referenced_ids="endpointIdLabel,endpointIdEd,clusterIdLabel,clusterIdEd,attributeIdLabel,attributeIdEd,eventIdLabel,eventIdEd,commandIdLabel,commandIdEd"
+ app:constraint_referenced_ids="endpointIdLabel,endpointIdEd,clusterIdLabel,clusterIdEd,attributeIdLabel,attributeIdEd,eventIdLabel,eventIdEd,commandIdLabel,commandIdEd,isUrgentLabel,isUrgentSp"
app:flow_horizontalBias="0.0"
app:flow_horizontalGap="8dp"
app:flow_horizontalStyle="packed"
@@ -28,7 +64,7 @@
app:flow_wrapMode="aligned"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/addressUpdateFragment" />
+ app:layout_constraintTop_toBottomOf="@id/selectTypeRadioGroup" />
<TextView
android:id="@+id/endpointIdLabel"
@@ -98,6 +134,7 @@
android:layout_height="wrap_content"
android:padding="8dp"
android:textSize="16sp"
+ android:visibility="gone"
android:text="@string/command_id_label" />
<EditText
@@ -106,91 +143,104 @@
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:inputType="number"
+ android:visibility="gone"
android:hint="@string/wildcard_help_label"/>
- <Button
- android:id="@+id/readBtn"
+ <TextView
+ android:id="@+id/isUrgentLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="16dp"
- android:layout_marginTop="16dp"
- android:layout_marginBottom="8dp"
- android:layout_gravity="center"
- android:text="@string/wildcard_read_btn_text"
+ android:padding="8dp"
android:textSize="16sp"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toStartOf="@id/writeBtn"
- app:layout_constraintTop_toBottomOf="@id/flow"/>
+ android:visibility="gone"
+ android:text="@string/isUrgent_label"/>
- <Button
- android:id="@+id/writeBtn"
- android:layout_width="wrap_content"
+ <Spinner
+ android:id="@+id/isUrgentSp"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:padding="16dp"
- android:layout_marginTop="16dp"
- android:layout_marginBottom="8dp"
- android:layout_gravity="center"
- android:text="@string/wildcard_write_btn_text"
+ android:hint="@string/isUrgent_label"
+ android:entries="@array/chip_select_menu"
+ android:inputType="text"
+ android:spinnerMode="dropdown"
android:textSize="16sp"
- app:layout_constraintStart_toEndOf="@id/readBtn"
- app:layout_constraintEnd_toStartOf="@id/invokeBtn"
- app:layout_constraintTop_toBottomOf="@id/flow"/>
+ android:visibility="gone"/>
- <Button
- android:id="@+id/invokeBtn"
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/addLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="16dp"
- android:layout_marginTop="16dp"
- android:layout_marginBottom="8dp"
- android:layout_gravity="center"
- android:text="@string/wildcard_invoke_btn_text"
- android:textSize="16sp"
- app:layout_constraintStart_toEndOf="@id/writeBtn"
- app:layout_constraintEnd_toStartOf="@id/subscribeBtn"
- app:layout_constraintTop_toBottomOf="@id/flow"/>
-
- <Button
- android:id="@+id/subscribeBtn"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="16dp"
- android:layout_marginTop="16dp"
- android:layout_marginBottom="8dp"
- android:layout_gravity="center"
- android:text="@string/wildcard_subscribe_btn_text"
- android:textSize="16sp"
- app:layout_constraintStart_toEndOf="@id/invokeBtn"
+ android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toBottomOf="@id/flow"/>
-
- <Button
- android:id="@+id/readEventBtn"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="16dp"
- android:layout_marginTop="16dp"
- android:layout_marginBottom="8dp"
- android:layout_gravity="center"
- android:text="@string/wildcard_read_event_btn_text"
- android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toStartOf="@id/subscribeEventBtn"
- app:layout_constraintTop_toBottomOf="@id/readBtn"/>
+ app:layout_constraintTop_toBottomOf="@id/flow">
+ <TextView
+ android:id="@+id/sendListView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"/>
+ <Button
+ android:id="@+id/addAttributeBtn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="16dp"
+ android:text="@string/wildcard_add_attribute_btn_text"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/addEventBtn"
+ app:layout_constraintTop_toBottomOf="@id/sendListView"
+ android:textSize="16sp" />
+ <Button
+ android:id="@+id/addEventBtn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="16dp"
+ android:text="@string/wildcard_add_event_btn_text"
+ app:layout_constraintStart_toEndOf="@id/addAttributeBtn"
+ app:layout_constraintEnd_toStartOf="@id/resetBtn"
+ app:layout_constraintTop_toBottomOf="@id/sendListView"
+ android:textSize="16sp" />
+ <Button
+ android:id="@+id/resetBtn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="16dp"
+ android:text="@string/wildcard_reset_btn_text"
+ app:layout_constraintStart_toEndOf="@id/addEventBtn"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/sendListView"
+ android:textSize="16sp" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ <Button
+ android:id="@+id/sendBtn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="16dp"
+ android:layout_marginTop="16dp"
+ android:layout_marginBottom="8dp"
+ android:layout_gravity="center"
+ android:text="@string/wildcard_send_btn_text"
+ android:textSize="16sp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/shutdownSubscriptionBtn"
+ app:layout_constraintTop_toBottomOf="@id/addLayout"/>
<Button
- android:id="@+id/subscribeEventBtn"
+ android:id="@+id/shutdownSubscriptionBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="8dp"
android:layout_gravity="center"
- android:text="@string/wildcard_subscribe_event_btn_text"
+ android:text="@string/wildcard_shutdown_subscription_btn_text"
android:textSize="16sp"
- app:layout_constraintStart_toEndOf="@id/readEventBtn"
+ android:visibility="gone"
+ app:layout_constraintStart_toEndOf="@id/sendBtn"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toBottomOf="@id/subscribeBtn"/>
+ app:layout_constraintTop_toBottomOf="@id/addLayout"/>
<ScrollView
android:layout_width="match_parent"
@@ -198,7 +248,7 @@
android:fadeScrollbars="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/subscribeEventBtn">
+ app:layout_constraintTop_toBottomOf="@id/sendBtn">
<TextView
android:id="@+id/outputTv"
android:layout_width="match_parent"
@@ -208,6 +258,4 @@
android:singleLine="false"
android:textSize="20sp" />
</ScrollView>
-
-
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/examples/android/CHIPTool/app/src/main/res/values/strings.xml b/examples/android/CHIPTool/app/src/main/res/values/strings.xml
index 7ca5726..5a37d3e 100644
--- a/examples/android/CHIPTool/app/src/main/res/values/strings.xml
+++ b/examples/android/CHIPTool/app/src/main/res/values/strings.xml
@@ -142,7 +142,6 @@
<string name="subscribe_dialog_subscribe_btn_text">Subscribe</string>
<string name="subscribe_dialog_min_interval_hint">Minimum interval (seconds)</string>
<string name="subscribe_dialog_max_interval_hint">Maximum interval (seconds)</string>
- <string name="subscribe_dialog_is_urgent_hint">is Urgent Event (bool)</string>
<string name="subscribe_dialog_keep_subscriptions_hint">keep subscriptions (bool)</string>
<string name="subscribe_dialog_is_fabric_filtered_hint">is Fabric Filtered (bool)</string>
@@ -163,18 +162,32 @@
<string name="invoke_dialog_im_timeout_hint">Timeout</string>
<string name="invoke_dialog_user_guide_hint">Usage : [Type]:[Value],[Type]:[Value]\nType:UnsignedInt, Int, Boolean, Float, Double, String, ByteArray(Hex)\nExample:\nLevelControlCluster, moveToLevel : UnsignedInt:100,UnsignedInt:0</string>
+ <string name="shutdown_dialog_title_text">Shutdown Subscription</string>
+ <string name="shutdown_dialog_fabric_index_hint">Fabric Index</string>
+ <string name="shutdown_dialog_subscription_id_hint">Subscription Id</string>
+ <string name="shutdown_dialog_shutdown_btn_text">Shutdown</string>
+ <string name="shutdown_dialog_shutdown_all_btn_text">Shutdown All</string>
+
<string name="endpoint_id_label">Endpoint ID</string>
<string name="cluster_id_label">Cluster ID</string>
<string name="attribute_id_label">Attribute ID</string>
<string name="event_id_label">Event ID</string>
<string name="command_id_label">Command ID</string>
+ <string name="isUrgent_label">isUrgent</string>
<string name="wildcard_help_label">Leave blank for wildcard</string>
<string name="wildcard_subscribe_btn_text">Subscribe</string>
<string name="wildcard_read_btn_text">Read</string>
<string name="wildcard_invoke_btn_text">Invoke</string>
<string name="wildcard_write_btn_text">Write</string>
+ <string name="wildcard_add_attribute_btn_text">Add Attribute</string>
+ <string name="wildcard_add_event_btn_text">Add Event</string>
+ <string name="wildcard_reset_btn_text">Reset</string>
+ <string name="wildcard_send_btn_text">Send</string>
+ <string name="wildcard_shutdown_subscription_btn_text">Shutdown Subscription</string>
<string name="wildcard_subscribe_event_btn_text">Subscribe Event</string>
<string name="wildcard_read_event_btn_text">Read Event</string>
+ <string name="wildcard_empty_error_toast_message">Please add it to the list using Add Button.</string>
+ <string name="wildcard_subscribe_established_toast_message">Subscription established</string>
<string name="provision_custom_flow_btn_text">Provision CHIP device with Custom Flow</string>
<string name="chip_device_info_commissioning_flow_label">Commissioning Flow:</string>