Skip to content

Commit

Permalink
Display endpoint list (#10942)
Browse files Browse the repository at this point in the history
* basic code generation template, but not able to import to tool app

create new public class under chip/clusterinfo

* change package

* no error code generation

* new design solution

* need to wait for cast-helper

* callback generation done

* on/off commands working

* revert .idea changes

* one more .idea change revert

* remove outline.java

* Restyled by whitespace

* Restyled by google-java-format

* Restyled by gn

* Restyled by google-java-format

* fix merge

* merge conflict

* fix comments

* Restyled by gn

* resolve type, nullable and format comments

* resolve build issues

* Restyled by gn

* update zap generated file

* add descriptive documentation on each new class

* Restyled by google-java-format

* modify description of each new added class

* Restyled by google-java-format

* add . at the end of class description

* Restyled by google-java-format

* add recycler view to display endpoint

* recycler view for endpoint display and test cluster detail screen done

* change number of hard-coded enpoint to 2

* endpoint first draft done

* resolve conflict

* remove duplicate todo

* fix comments

* Restyled by whitespace

* resolve comments

* fix comments

Co-authored-by: Restyled.io <[email protected]>
  • Loading branch information
2 people authored and pull[bot] committed Feb 25, 2022
1 parent 8ca2195 commit 2d17b84
Show file tree
Hide file tree
Showing 11 changed files with 195 additions and 221 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import chip.setuppayload.SetupPayload
import chip.setuppayload.SetupPayloadParser
import chip.setuppayload.SetupPayloadParser.UnrecognizedQrCodeException
import com.google.chip.chiptool.attestation.AttestationTestFragment
import com.google.chip.chiptool.clusterclient.ClusterInteractionFragment
import com.google.chip.chiptool.clusterclient.clusterinteraction.ClusterInteractionFragment
import com.google.chip.chiptool.clusterclient.MultiAdminClientFragment
import com.google.chip.chiptool.clusterclient.OpCredClientFragment
import com.google.chip.chiptool.clusterclient.BasicClientFragment
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.google.chip.chiptool.clusterclient.clusterinteraction

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import chip.devicecontroller.ChipDeviceController
import com.google.chip.chiptool.ChipClient
import com.google.chip.chiptool.GenericChipDeviceListener
import com.google.chip.chiptool.R
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel

/**
* ClusterDetailFragment allows user to pick cluster, command, specify parameters and see
* the callback result.
*/
class ClusterDetailFragment : Fragment(){
private val deviceController: ChipDeviceController
get() = ChipClient.getDeviceController(requireContext())

private val scope = CoroutineScope(Dispatchers.Main + Job())

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.cluster_detail_fragment, container, false).apply {
deviceController.setCompletionListener(GenericChipDeviceListener())
}
}

private fun showMessage(msg: String) {
requireActivity().runOnUiThread {
Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show()
}
}

override fun onStop() {
super.onStop()
scope.cancel()
}

companion object {
private const val TAG = "ClusterDetailFragment"
fun newInstance(): ClusterDetailFragment = ClusterDetailFragment()
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.google.chip.chiptool.clusterclient
package com.google.chip.chiptool.clusterclient.clusterinteraction

import android.os.Bundle
import android.util.Log
Expand All @@ -7,9 +7,8 @@ import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import chip.clusterinfo.ClusterCommandCallback
import androidx.recyclerview.widget.LinearLayoutManager
import chip.clusterinfo.ClusterInfo
import chip.clusterinfo.CommandInfo
import chip.devicecontroller.ChipDeviceController
import com.google.chip.chiptool.ChipClient
import com.google.chip.chiptool.GenericChipDeviceListener
Expand All @@ -19,8 +18,9 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import chip.devicecontroller.ClusterInfoMapping
import java.lang.Exception
import kotlinx.android.synthetic.main.cluster_interaction_fragment.view.getClusterMappingBtn
import com.google.chip.chiptool.clusterclient.AddressUpdateFragment
import kotlinx.android.synthetic.main.cluster_interaction_fragment.view.endpointList
import kotlinx.android.synthetic.main.cluster_interaction_fragment.view.getEndpointListBtn
import kotlinx.coroutines.launch

class ClusterInteractionFragment : Fragment() {
Expand All @@ -38,41 +38,25 @@ class ClusterInteractionFragment : Fragment() {
): View {
return inflater.inflate(R.layout.cluster_interaction_fragment, container, false).apply {
deviceController.setCompletionListener(ChipControllerCallback())
addressUpdateFragment =
childFragmentManager.findFragmentById(R.id.addressUpdateFragment) as AddressUpdateFragment
clusterMap = ClusterInfoMapping().clusterMap;
getClusterMappingBtn.setOnClickListener { scope.launch { getClusterMapping() } }
}
}

private suspend fun getClusterMapping() {
// In real code: "OnOff" would be selected by the user.
val methodSelected = "onOff"
showMessage(methodSelected + " is initialized")
val selectedClusterInfo = clusterMap[methodSelected]!!
val devicePtr =
ChipClient.getConnectedDevicePointer(requireContext(), addressUpdateFragment.deviceId)
val endpointId = 1
val selectedCluster = selectedClusterInfo.createClusterFunction.create(devicePtr, endpointId)
// Imagine user wants to execute the command "OffWithEffect", pass the string here
val selectedCommandInfo: CommandInfo = selectedClusterInfo.commands["on"]!!

var selectedCommandCallback = selectedCommandInfo.commandCallbackSupplier.get()
selectedCommandCallback?.setCallbackDelegate(object : ClusterCommandCallback {
override fun onSuccess(responseValues: List<Any>) {
showMessage("Command success")
// Populate UI based on response values. We know the types from CommandInfo.getCommandResponses().
responseValues.forEach { Log.d(TAG, it.toString()) }
getEndpointListBtn.setOnClickListener {
scope.launch {
showMessage("Retrieving endpoints")
endpointList.visibility = View.VISIBLE
}
}

override fun onFailure(exception: Exception) {
showMessage("Command failed")
Log.e(TAG, exception.toString())
addressUpdateFragment =
childFragmentManager.findFragmentById(R.id.addressUpdateFragment) as AddressUpdateFragment
clusterMap = ClusterInfoMapping().clusterMap
var dataList: List<EndpointItem> = ArrayList()
// TODO: Dynamically retrieve endpoint information using descriptor cluster
// hardcode the endpoint for now
for (i in 0 until 2) {
dataList += EndpointItem(i)
}
})

var commandArguments: HashMap<String, Any> = HashMap<String, Any>()
selectedCommandInfo.getCommandFunction().invokeCommand(selectedCluster, selectedCommandCallback, commandArguments)
endpointList.adapter = EndpointAdapter(dataList, EndpointListener())
endpointList.layoutManager = LinearLayoutManager(requireContext())
}
}

private fun showMessage(msg: String) {
Expand Down Expand Up @@ -109,4 +93,23 @@ class ClusterInteractionFragment : Fragment() {
private const val TAG = "ClusterInteractionFragment"
fun newInstance(): ClusterInteractionFragment = ClusterInteractionFragment()
}

private fun showFragment(fragment: Fragment, showOnBack: Boolean = true) {
val fragmentTransaction = requireActivity().supportFragmentManager
.beginTransaction()
.replace(R.id.fragment_container, fragment, fragment.javaClass.simpleName)

if (showOnBack) {
fragmentTransaction.addToBackStack(null)
}

fragmentTransaction.commit()
}

inner class EndpointListener : EndpointAdapter.OnItemClickListener {
override fun onItemClick(position: Int) {
Toast.makeText(requireContext(), "Item $position clicked", Toast.LENGTH_SHORT).show()
showFragment(ClusterDetailFragment.newInstance())
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.google.chip.chiptool.clusterclient.clusterinteraction

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.google.chip.chiptool.R

/**
* EndpointAdapter implements the endpointList(RecycleView) Adapter and associates different
* endpoint with the same onClick function provided in [ClusterInteractionFragment.EndpointListener]
*/
class EndpointAdapter(
private val endpointList: List<EndpointItem>,
private val listener: OnItemClickListener
) : RecyclerView.Adapter<EndpointAdapter.EndpointViewHolder>() {

inner class EndpointViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
View.OnClickListener {
val endpointId: TextView = itemView.findViewById(R.id.endpointTv)

init {
itemView.setOnClickListener(this)
}

override fun onClick(endpointItem: View) {
val position = this.adapterPosition
if (position != RecyclerView.NO_POSITION) {
listener.onItemClick(position)
}
}
}

interface OnItemClickListener {
fun onItemClick(position: Int)
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EndpointViewHolder {
val itemView =
LayoutInflater.from(parent.context).inflate(R.layout.endpoint_item, parent, false)
return EndpointViewHolder(itemView)
}

override fun onBindViewHolder(holder: EndpointViewHolder, position: Int) {
holder.endpointId.text = endpointList[position].endpointId.toString()
}

override fun getItemCount(): Int {
return endpointList.size
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.google.chip.chiptool.clusterclient.clusterinteraction

data class EndpointItem(val endpointId: Int)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

</androidx.constraintlayout.widget.ConstraintLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
android:layout_height="match_parent">

<Button
android:id="@+id/getClusterMappingBtn"
android:id="@+id/getEndpointListBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="132dp"
android:layout_marginStart="16dp"
android:text="Button"
android:text="@string/retrieve_endpoint_list"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.fragment.app.FragmentContainerView
Expand All @@ -26,10 +26,9 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/endpointList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="180dp"
android:layout_height="wrap_content"
android:clipToPadding="false"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/addressUpdateFragment" />
app:layout_constraintTop_toBottomOf="@+id/getEndpointListBtn" />

</androidx.constraintlayout.widget.ConstraintLayout>
30 changes: 30 additions & 0 deletions src/android/CHIPTool/app/src/main/res/layout/endpoint_item.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp"
android:layout_margin="4dp">

<TextView
android:id="@+id/endpointTv"
android:textStyle="bold"
android:width="100dp"
android:height="70dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:textColor="@android:color/black"
android:textSize="18sp"
android:background="@color/cardview_shadow_start_color"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.cardview.widget.CardView>
4 changes: 2 additions & 2 deletions src/android/CHIPTool/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
<string name="op_cred_client_btn_text">Operational Credentials cluster</string>
<string name="op_cred_client_read_supported_fabric_btn_text">Read Supported Fabric count</string>
<string name="op_cred_client_read_commissioned_fabric_btn_text">Read Commissioned Fabric count</string>

<string name="basic_cluster_btn_text">Basic cluster</string>
<string name="basic_cluster_read_user_label_btn_text">Read User Label</string>
<string name="basic_cluster_write_user_label_btn_text">Write User Label</string>
Expand All @@ -123,5 +123,5 @@
<string name="dcl_response_key">result</string>
<string name="dcl_custom_flow_url_key">custom</string>
<string name="custom_flow_return_url"></string>

<string name="retrieve_endpoint_list">Retrieve Endpoint List</string>
</resources>
4 changes: 2 additions & 2 deletions src/controller/java/templates/ClusterInfo-java.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public class ClusterInfoMapping {
Map<String, CommandInfo> {{asLowerCamelCase name}}ClusterCommandInfoMap = new LinkedHashMap<>();
{{#chip_cluster_commands}}
Map<String, CommandParameterInfo> {{asLowerCamelCase ../name}}{{asLowerCamelCase name}}CommandParams = new LinkedHashMap<String, CommandParameterInfo>();
// PLEASE UPDATE LATER: fill out parameter types
{{! TODO: fill out parameter types }}
{{#if (zcl_command_arguments_count this.id)}}
{{#if hasSpecificResponse}}
CommandParameterInfo {{asLowerCamelCase ../name}}{{asLowerCamelCase name}}CommandParameterInfo = new CommandParameterInfo("{{asUpperCamelCase ../name}}", ChipClusters.{{asUpperCamelCase ../name}}Cluster.{{asUpperCamelCase responseName}}Callback.class);
Expand Down Expand Up @@ -150,4 +150,4 @@ public class ClusterInfoMapping {
}
}

{{/if}}
{{/if}}
Loading

0 comments on commit 2d17b84

Please sign in to comment.