From 7e520beb23a284a9143cd6914b1ead36cf92d362 Mon Sep 17 00:00:00 2001 From: joonhaengHeo <85541460+joonhaengHeo@users.noreply.github.com> Date: Wed, 27 Sep 2023 20:32:16 +0900 Subject: [PATCH] [Android] Support group message (#29244) * Implement Android Group message * Add Android if_nameindex * Add groupsetting API * remove test code * Restyled by whitespace * Restyled by google-java-format * Restyled by clang-format * Implement Group Setting UI * restyle kotlin * Fix kotlin static code analysis * Modify from comments. * Restyled by whitespace * Restyled by google-java-format * Restyled by clang-format * kotlin restyle * Modify return value * Update group id in commandpath * Update kotlin codestyle * Restyled by google-java-format * Restyled by clang-format * Update from comments * Modify write path in group session --------- Co-authored-by: Restyled.io --- .../google/chip/chiptool/CHIPToolActivity.kt | 4 +- .../chip/chiptool/SelectActionFragment.kt | 6 + .../clusterclient/AddressUpdateFragment.kt | 65 +- .../clusterclient/GroupSettingFragment.kt | 642 ++++++++++++++++++ .../clusterclient/WildcardFragment.kt | 23 +- .../DeviceProvisioningFragment.kt | 4 +- .../google/chip/chiptool/util/DeviceIdUtil.kt | 25 + .../res/layout/add_access_control_dialog.xml | 59 ++ .../src/main/res/layout/add_group_dialog.xml | 56 ++ .../main/res/layout/add_key_set_dialog.xml | 84 +++ .../res/layout/address_update_fragment.xml | 18 + .../main/res/layout/bind_key_set_dialog.xml | 76 +++ .../res/layout/group_setting_fragment.xml | 151 ++++ .../main/res/layout/remove_group_dialog.xml | 46 ++ .../main/res/layout/remove_key_set_dialog.xml | 46 ++ .../res/layout/select_action_fragment.xml | 8 + .../main/res/layout/send_key_set_dialog.xml | 136 ++++ .../main/res/layout/set_key_write_dialog.xml | 48 ++ .../res/layout/write_group_key_dialog.xml | 48 ++ .../app/src/main/res/values/strings.xml | 35 + kotlin-detect-config.yaml | 1 + src/controller/CHIPDeviceController.h | 10 + .../java/AndroidDeviceControllerWrapper.cpp | 1 + src/controller/java/BUILD.gn | 1 + .../java/CHIPDeviceController-JNI.cpp | 428 +++++++++++- src/controller/java/GroupDeviceProxy.h | 35 + .../ChipDeviceController.java | 77 +++ .../GroupKeySecurityPolicy.java | 44 ++ .../model/AttributeWriteRequest.java | 5 +- .../devicecontroller/model/InvokeElement.java | 46 +- src/inet/InetInterface.cpp | 142 ++++ src/platform/android/InetPlatformConfig.h | 4 + 32 files changed, 2347 insertions(+), 27 deletions(-) create mode 100644 examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/GroupSettingFragment.kt create mode 100644 examples/android/CHIPTool/app/src/main/res/layout/add_access_control_dialog.xml create mode 100644 examples/android/CHIPTool/app/src/main/res/layout/add_group_dialog.xml create mode 100644 examples/android/CHIPTool/app/src/main/res/layout/add_key_set_dialog.xml create mode 100644 examples/android/CHIPTool/app/src/main/res/layout/bind_key_set_dialog.xml create mode 100644 examples/android/CHIPTool/app/src/main/res/layout/group_setting_fragment.xml create mode 100644 examples/android/CHIPTool/app/src/main/res/layout/remove_group_dialog.xml create mode 100644 examples/android/CHIPTool/app/src/main/res/layout/remove_key_set_dialog.xml create mode 100644 examples/android/CHIPTool/app/src/main/res/layout/send_key_set_dialog.xml create mode 100644 examples/android/CHIPTool/app/src/main/res/layout/set_key_write_dialog.xml create mode 100644 examples/android/CHIPTool/app/src/main/res/layout/write_group_key_dialog.xml create mode 100644 src/controller/java/GroupDeviceProxy.h create mode 100644 src/controller/java/src/chip/devicecontroller/GroupKeySecurityPolicy.java diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/CHIPToolActivity.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/CHIPToolActivity.kt index 0284b007fe60ec..13f919ec057a9c 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/CHIPToolActivity.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/CHIPToolActivity.kt @@ -39,6 +39,7 @@ import com.google.chip.chiptool.setuppayloadscanner.BarcodeFragment import com.google.chip.chiptool.setuppayloadscanner.CHIPDeviceDetailsFragment import com.google.chip.chiptool.setuppayloadscanner.CHIPDeviceInfo import com.google.chip.chiptool.setuppayloadscanner.CHIPLedgerDetailsFragment +import com.google.chip.chiptool.util.DeviceIdUtil import org.json.JSONObject class CHIPToolActivity : @@ -94,11 +95,12 @@ class CHIPToolActivity : } } - override fun onCommissioningComplete(code: Int) { + override fun onCommissioningComplete(code: Int, nodeId: Long) { runOnUiThread { Toast.makeText(this, getString(R.string.commissioning_completed, code), Toast.LENGTH_SHORT) .show() } + DeviceIdUtil.setCommissionedNodeId(this, nodeId) ChipClient.getDeviceController(this).close() showFragment(SelectActionFragment.newInstance(), false) } diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/SelectActionFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/SelectActionFragment.kt index 5932acb648d8a5..571552b86f06b2 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/SelectActionFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/SelectActionFragment.kt @@ -30,6 +30,7 @@ import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import com.google.chip.chiptool.attestation.AttestationTestFragment import com.google.chip.chiptool.clusterclient.* +import com.google.chip.chiptool.clusterclient.GroupSettingFragment import com.google.chip.chiptool.clusterclient.clusterinteraction.ClusterInteractionFragment import com.google.chip.chiptool.databinding.SelectActionFragmentBinding import com.google.chip.chiptool.provisioning.ProvisionNetworkType @@ -71,6 +72,7 @@ class SelectActionFragment : Fragment() { binding.provisionCustomFlowBtn.setOnClickListener { handleProvisionCustomFlowClicked() } binding.wildcardBtn.setOnClickListener { handleWildcardClicked() } binding.unpairDeviceBtn.setOnClickListener { handleUnpairDeviceClicked() } + binding.groupSettingBtn.setOnClickListener { handleGroupSettingClicked() } return binding.root } @@ -233,6 +235,10 @@ class SelectActionFragment : Fragment() { showFragment(BarcodeFragment.newInstance(), false) } + private fun handleGroupSettingClicked() { + showFragment(GroupSettingFragment.newInstance()) + } + companion object { @JvmStatic fun newInstance() = SelectActionFragment() diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/AddressUpdateFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/AddressUpdateFragment.kt index 2fc03050bfc2f1..b4c87dc53c6538 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/AddressUpdateFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/AddressUpdateFragment.kt @@ -1,9 +1,13 @@ package com.google.chip.chiptool.clusterclient +import android.content.Context import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.AdapterView +import android.widget.ArrayAdapter import androidx.fragment.app.Fragment import chip.devicecontroller.ChipDeviceController import com.google.chip.chiptool.ChipClient @@ -41,13 +45,70 @@ class AddressUpdateFragment : Fragment() { super.onViewCreated(view, savedInstanceState) val compressedFabricId = deviceController.compressedFabricId - binding.fabricIdEd.setText(compressedFabricId.toULong().toString(16).padStart(16, '0')) - binding.deviceIdEd.setText(DeviceIdUtil.getLastDeviceId(requireContext()).toString()) + binding.fabricIdEd.setText(compressedFabricId.toULong().toString().padStart(16, '0')) + binding.deviceIdEd.setText(DeviceIdUtil.getLastDeviceId(requireContext()).toString(16)) binding.epIdEd.setText(endpointId.toString()) + + updateDeviceIdSpinner() + } + + fun updateDeviceIdSpinner() { + val deviceIdList = DeviceIdUtil.getCommissionedNodeId(requireContext()) + binding.deviceIdSpinner.adapter = + ArrayAdapter(requireContext(), android.R.layout.simple_spinner_dropdown_item, deviceIdList) + binding.deviceIdSpinner.onItemSelectedListener = + object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + binding.deviceIdEd.setText(deviceIdList[position].toULong(16).toString()) + } + + override fun onNothingSelected(parent: AdapterView<*>?) { + Log.d(TAG, "onNothingSelected") + } + } } override fun onDestroyView() { super.onDestroyView() _binding = null } + + suspend fun getDevicePointer(context: Context): Long { + return if (isGroupId()) { + deviceController.getGroupDevicePointer(getGroupId().toInt()) + } else { + ChipClient.getConnectedDevicePointer(context, getNodeId().toLong()) + } + } + + fun isGroupId(): Boolean { + return isGroupNodeId(getNodeId()) + } + + fun getGroupId(): UInt { + return getGroupIdFromNodeId(getNodeId()) + } + + fun getNodeId(): ULong { + return binding.deviceIdEd.text.toString().toULong() + } + + companion object { + private const val TAG = "AddressUpdateFragment" + // Refer from NodeId.h (src/lib/core/NodeId.h) + private const val MIN_GROUP_NODE_ID = 0xFFFF_FFFF_FFFF_0000UL + private const val MASK_GROUP_ID = 0x0000_0000_0000_FFFFUL + + fun isGroupNodeId(nodeId: ULong): Boolean { + return nodeId >= MIN_GROUP_NODE_ID + } + + fun getNodeIdFromGroupId(groupId: UInt): ULong { + return groupId.toULong() or MIN_GROUP_NODE_ID + } + + fun getGroupIdFromNodeId(nodeId: ULong): UInt { + return (nodeId and MASK_GROUP_ID).toUInt() + } + } } diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/GroupSettingFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/GroupSettingFragment.kt new file mode 100644 index 00000000000000..d517fe7452018c --- /dev/null +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/GroupSettingFragment.kt @@ -0,0 +1,642 @@ +package com.google.chip.chiptool.clusterclient + +import android.app.AlertDialog +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ArrayAdapter +import android.widget.Button +import android.widget.EditText +import android.widget.Spinner +import androidx.fragment.app.Fragment +import androidx.lifecycle.lifecycleScope +import chip.devicecontroller.ChipDeviceController +import chip.devicecontroller.ClusterIDMapping +import chip.devicecontroller.GroupKeySecurityPolicy +import chip.devicecontroller.InvokeCallback +import chip.devicecontroller.ReportCallback +import chip.devicecontroller.WriteAttributesCallback +import chip.devicecontroller.cluster.structs.AccessControlClusterAccessControlEntryStruct +import chip.devicecontroller.cluster.structs.GroupKeyManagementClusterGroupKeySetStruct +import chip.devicecontroller.model.AttributeWriteRequest +import chip.devicecontroller.model.ChipAttributePath +import chip.devicecontroller.model.ChipEventPath +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.GenericChipDeviceListener +import com.google.chip.chiptool.R +import com.google.chip.chiptool.databinding.GroupSettingFragmentBinding +import com.google.chip.chiptool.util.DeviceIdUtil +import java.lang.Exception +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch + +class GroupSettingFragment : Fragment() { + private val deviceController: ChipDeviceController + get() = ChipClient.getDeviceController(requireContext()) + + private lateinit var scope: CoroutineScope + + private lateinit var addressUpdateFragment: AddressUpdateFragment + + private var _binding: GroupSettingFragmentBinding? = null + private val binding + get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = GroupSettingFragmentBinding.inflate(inflater, container, false) + scope = viewLifecycleOwner.lifecycleScope + + deviceController.setCompletionListener(ChipControllerCallback()) + + addressUpdateFragment = + childFragmentManager.findFragmentById(R.id.addressUpdateFragment) as AddressUpdateFragment + + binding.sendKeySetWriteBtn.setOnClickListener { sendKeySetWriteBtnClick() } + binding.writeGroupKeyMapBtn.setOnClickListener { writeGroupKeyMapBtnClick() } + binding.sendAddGroupBtn.setOnClickListener { sendAddGroupBtnClick() } + binding.addAccessControlBtn.setOnClickListener { scope.launch { readAccessControl() } } + binding.addGroupBtn.setOnClickListener { addGroupBtnClick() } + binding.removeGroupBtn.setOnClickListener { removeGroupBtnClick() } + binding.addkeysetBtn.setOnClickListener { addKeySetBtnClick() } + binding.removekeysetBtn.setOnClickListener { removeKeySetBtnClick() } + binding.bindkeysetBtn.setOnClickListener { bindKeySetBtnClick(true) } + binding.unbindkeysetBtn.setOnClickListener { bindKeySetBtnClick(false) } + + return binding.root + } + + private fun addGroupBtnClick() { + val dialogView = requireActivity().layoutInflater.inflate(R.layout.add_group_dialog, null) + val groupIdEd = dialogView.findViewById(R.id.groupIdEd) + val groupNameEd = dialogView.findViewById(R.id.groupNameEd) + + dialogView.findViewById