From 1126600094f95f5f675171c4ed0247048e9fc408 Mon Sep 17 00:00:00 2001 From: joonhaengHeo <85541460+joonhaengHeo@users.noreply.github.com> Date: Wed, 15 Mar 2023 02:21:35 +0900 Subject: [PATCH] Modify wildcardFragment for multiple attribute,event (#25677) --- .../clusterclient/WildcardFragment.kt | 289 +++++++++++++----- .../app/src/main/res/layout/read_dialog.xml | 4 +- .../res/layout/shutdown_subscribe_dialog.xml | 79 +++++ .../src/main/res/layout/subscribe_dialog.xml | 24 +- .../src/main/res/layout/wildcard_fragment.xml | 182 +++++++---- .../app/src/main/res/values/strings.xml | 15 +- 6 files changed, 418 insertions(+), 175 deletions(-) create mode 100644 examples/android/CHIPTool/app/src/main/res/layout/shutdown_subscribe_dialog.xml 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 a9861aa4223fa5..70d18492f83968 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.Button 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.InvokeElement 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.lang.StringBuilder 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 @@ class WildcardFragment : Fragment() { private lateinit var addressUpdateFragment: AddressUpdateFragment + private val attributePath = ArrayList() + private val eventPath = ArrayList() + private val subscribeIdList = ArrayList() + private val reportCallback = object : ReportCallback { override fun onError(attributePath: ChipAttributePath?, eventPath: ChipEventPath?, ex: Exception) { if (attributePath != null) @@ -108,12 +116,42 @@ class WildcardFragment : Fragment() { ): 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 @@ class WildcardFragment : Fragment() { 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 @@ class WildcardFragment : Fragment() { 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 @@ class WildcardFragment : Fragment() { 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 @@ class WildcardFragment : Fragment() { val isFabricFilteredEd = dialogView.findViewById(R.id.isFabricFilteredSp) dialogView.findViewById