Skip to content

Commit

Permalink
Implemented support for T&C
Browse files Browse the repository at this point in the history
  • Loading branch information
swan-amazon committed Jul 30, 2024
1 parent 783f268 commit 233d775
Show file tree
Hide file tree
Showing 38 changed files with 1,864 additions and 197 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7508,11 +7508,15 @@ endpoint 0 {
callback attribute regulatoryConfig;
callback attribute locationCapability;
callback attribute supportsConcurrentConnection;
ram attribute TCAcceptedVersion;
ram attribute TCMinRequiredVersion default = 1;
ram attribute TCAcknowledgements default = 0x0000;
ram attribute TCAcknowledgementsRequired default = true;
callback attribute generatedCommandList;
callback attribute acceptedCommandList;
callback attribute eventList;
callback attribute attributeList;
ram attribute featureMap default = 0;
ram attribute featureMap default = 1;
ram attribute clusterRevision default = 1;

handle command ArmFailSafe;
Expand All @@ -7521,6 +7525,8 @@ endpoint 0 {
handle command SetRegulatoryConfigResponse;
handle command CommissioningComplete;
handle command CommissioningCompleteResponse;
handle command SetTCAcknowledgements;
handle command SetTCAcknowledgementsResponse;
}

server cluster NetworkCommissioning {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2124,6 +2124,7 @@
"define": "GENERAL_COMMISSIONING_CLUSTER",
"side": "server",
"enabled": 1,
"apiMaturity": "provisional",
"commands": [
{
"name": "ArmFailSafe",
Expand Down Expand Up @@ -2172,6 +2173,22 @@
"source": "server",
"isIncoming": 0,
"isEnabled": 1
},
{
"name": "SetTCAcknowledgements",
"code": 6,
"mfgCode": null,
"source": "client",
"isIncoming": 1,
"isEnabled": 1
},
{
"name": "SetTCAcknowledgementsResponse",
"code": 7,
"mfgCode": null,
"source": "server",
"isIncoming": 0,
"isEnabled": 1
}
],
"attributes": [
Expand Down Expand Up @@ -2255,6 +2272,70 @@
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "TCAcceptedVersion",
"code": 5,
"mfgCode": null,
"side": "server",
"type": "int16u",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "TCMinRequiredVersion",
"code": 6,
"mfgCode": null,
"side": "server",
"type": "int16u",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "1",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "TCAcknowledgements",
"code": 7,
"mfgCode": null,
"side": "server",
"type": "bitmap16",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0x0000",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "TCAcknowledgementsRequired",
"code": 8,
"mfgCode": null,
"side": "server",
"type": "boolean",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "true",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "GeneratedCommandList",
"code": 65528,
Expand Down Expand Up @@ -2329,7 +2410,7 @@
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0",
"defaultValue": "1",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
Expand Down
23 changes: 22 additions & 1 deletion examples/all-clusters-app/linux/include/CHIPProjectAppConfig.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2022 Project CHIP Authors
* Copyright (c) 2022-2024 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -51,3 +51,24 @@
// Claim a device type while advertising that matches the device type on our
// endpoint 1. 0x0101 is the "Dimmable Light" device type.
#define CHIP_DEVICE_CONFIG_DEVICE_TYPE 0x0101

/**
* @brief Configures the required terms and conditions acknowledgements.
*
* This macro defines the required terms and conditions acknowledgements bitmask. The bit-field is 16 bits long, so the possible
* value range is [0, 65535). This setting can be used to require that terms and conditions are presented to the user during
* commissioning.
*/
#define CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS 1 // Require that terms and conditions ordinal 1 must be accepted.

/**
* @brief Configures the latest known version of the terms and conditions.
*
* This macro defines the version number of the latest terms and conditions. It allows the application to iterate on revisions of
* the terms and conditions. A value of 0 indicates that no specific version is required. This setting can be used to enforce
* version-specific terms and conditions acknowledgements in the application. When the set of terms and conditions needs to be
* changes, the version number should be monotomically increased. If the lateast terms and conditions version is updated (most
* likely during an OTA) then this may signal to the Administrator that updated terms and conditions should be presented to the
* user.
*/
#define CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION 1 // The current terms and conditions revision is 1.
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ class CHIPToolActivity :
startActivity(redirectIntent)
}

override fun handleEnhancedSetupFlowClicked() {
Toast.makeText(this, "Enhanced Setup Flow", Toast.LENGTH_SHORT).show()
showFragment(DeviceProvisioningFragment.newInstance(deviceInfo!!, null))
}

override fun setNetworkType(type: ProvisionNetworkType?) {
networkType = type
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,12 @@ open class GenericChipDeviceListener : ChipDeviceController.CompletionListener {
override fun onICDRegistrationComplete(errorCode: Long, icdDeviceInfo: ICDDeviceInfo) {
// No op
}

override fun onTermsAndConditionsRequired() {
// No op
}

override fun onTermsAndConditionsRequiredComplete(termsAndConditionsAcknowledgements: Int, termsAndConditionsVersion: Int) {
// No op
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class SelectActionFragment : Fragment() {
binding.basicClusterBtn.setOnClickListener { handleBasicClicked() }
binding.attestationTestBtn.setOnClickListener { handleAttestationTestClicked() }
binding.clusterInteractionBtn.setOnClickListener { handleClusterInteractionClicked() }
binding.provisionCustomFlowBtn.setOnClickListener { handleProvisionCustomFlowClicked() }
binding.provisionCustomFlowReadFromLedgerBtn.setOnClickListener { handleProvisionCustomFlowClicked() }
binding.wildcardBtn.setOnClickListener { handleWildcardClicked() }
binding.unpairDeviceBtn.setOnClickListener { handleUnpairDeviceClicked() }
binding.groupSettingBtn.setOnClickListener { handleGroupSettingClicked() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,14 @@ class DeviceProvisioningFragment : Fragment() {
.show()
}
}

override fun onTermsAndConditionsRequired() {
}

override fun onTermsAndConditionsRequiredComplete(termsAndConditionsAcknowledgements: Int, termsAndConditionsVersion: Int) {
Log.d(TAG, "onTermsAndConditionsRequiredComplete: $termsAndConditionsAcknowledgements, $termsAndConditionsVersion")
deviceController.updateTermsAndConditionsAcknowledgements(termsAndConditionsAcknowledgements, termsAndConditionsVersion)
}
}

private fun ByteArray.toHex(): String =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ class CHIPDeviceDetailsFragment : Fragment() {

// commissioningFlow = 2 (Custom), read device info from Ledger
if (deviceInfo.commissioningFlow == 2) {
binding.customFlowBtn.visibility = View.VISIBLE
binding.customFlowBtn.setOnClickListener {
binding.customFlowReadFromLedgerBtn.visibility = View.VISIBLE
binding.customFlowReadFromLedgerBtn.setOnClickListener {
FragmentUtil.getHost(this@CHIPDeviceDetailsFragment, Callback::class.java)
?.handleReadFromLedgerClicked(deviceInfo)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,19 @@ import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import com.android.volley.Request
import com.android.volley.Response.Listener
import com.android.volley.toolbox.JsonObjectRequest
import com.android.volley.toolbox.Volley
import com.google.chip.chiptool.R
import com.google.chip.chiptool.databinding.ChipLedgerInfoFragmentBinding
import com.google.chip.chiptool.util.FragmentUtil
import com.google.gson.Gson
import java.io.BufferedReader
import java.io.InputStreamReader
import org.json.JSONObject

/** Show the [CHIPDeviceInfo] from Ledger */
class CHIPLedgerDetailsFragment : Fragment() {
Expand All @@ -55,61 +60,50 @@ class CHIPLedgerDetailsFragment : Fragment() {

// Ledger api url
val url =
Uri.parse(context!!.getString(R.string.dcl_api_root_url))
Uri.parse(DCL_API_ROOT_URL)
.buildUpon()
.appendPath("${deviceInfo.vendorId}")
.appendPath("${deviceInfo.productId}")
.build()
.toString()
Log.d(TAG, "Dcl request Url: $url")

// Ledger API call
val jsonObjectRequest =
JsonObjectRequest(
Request.Method.GET,
url,
null,
{ response ->
Log.d(TAG, "Response from dcl $response")

// parse redirect Url
val responseJson = response.getJSONObject(context!!.getString(R.string.dcl_response_key))
val redirectUrl =
responseJson.getString(context!!.getString(R.string.dcl_custom_flow_url_key))
Log.d(TAG, "Redirect Url from Ledger: $redirectUrl")
binding.commissioningFlowUrlTv.text = redirectUrl

// generate redirect payload
val gson = Gson()
val payloadJson = gson.toJson(deviceInfo)
val payloadBase64 = Base64.encodeToString(payloadJson.toByteArray(), Base64.DEFAULT)
val redirectUrlWithPayload =
Uri.parse(redirectUrl)
.buildUpon()
.appendQueryParameter("payload", payloadBase64)
.appendQueryParameter(
"returnUrl",
context!!.getString(R.string.custom_flow_return_url)
)
.build()
.toString()

Log.d(TAG, "Redirect Url with Payload: $redirectUrlWithPayload")
binding.redirectBtn.setOnClickListener {
FragmentUtil.getHost(this@CHIPLedgerDetailsFragment, Callback::class.java)
?.handleCustomFlowRedirectClicked(redirectUrlWithPayload)
}
val context = getContext()!!
val mockDclRequestsResponsesRaw = readRawResourceFile(R.raw.mock_dcl_responses_json)
val mockDclRequestsResponses: org.json.JSONArray = org.json.JSONArray(mockDclRequestsResponsesRaw)

val mockDclRequestsResponseMap = HashMap<String, org.json.JSONObject>()
for (i in 0 until mockDclRequestsResponses.length()) {
val mockDclRequestsResponse = mockDclRequestsResponses.getJSONObject(i)

val mockDclRequest: org.json.JSONObject = mockDclRequestsResponse.getJSONObject("request")
val mockDclResponse: org.json.JSONObject = mockDclRequestsResponse.getJSONObject("response")

// enable redirect button
binding.redirectBtn.visibility = View.VISIBLE
},
{ error ->
Log.e(TAG, "Dcl request failed: $error")
binding.commissioningFlowUrlTv.text =
context!!.getString(R.string.chip_ledger_info_commissioning_flow_url_not_available)
}
)
queue.add(jsonObjectRequest)
val mockDclRequestURL = mockDclRequest.getString("url")
val mockDclResponseBody = mockDclResponse.getJSONObject("body")

mockDclRequestsResponseMap.put(mockDclRequestURL, mockDclResponseBody)
Log.d(TAG, "mockDclRequestURL= $mockDclRequestURL")
Log.d(TAG, "mockDclResponseBody= $mockDclResponseBody")
}

Log.d(TAG, "Request url= $url")
val response: org.json.JSONObject = mockDclRequestsResponseMap.get(url.toString())!!
Log.d(TAG, "Response from dcl $response")
Toast.makeText(context, "Enhanced Setup Flow: $response", Toast.LENGTH_LONG).show()

val enhancedSetupFlowOptions = response.optInt("enhancedSetupFlowOptions", 0)

if (0 != (enhancedSetupFlowOptions and 0b00000001)) {
Toast.makeText(context, "Enhanced Setup Flow supported!", Toast.LENGTH_SHORT).show()

binding.commissionBtn.setOnClickListener {
FragmentUtil.getHost(this@CHIPLedgerDetailsFragment, Callback::class.java)
?.handleEnhancedSetupFlowClicked()
}

binding.commissionBtn.visibility = View.VISIBLE
}

return binding.root
}
Expand All @@ -119,15 +113,40 @@ class CHIPLedgerDetailsFragment : Fragment() {
_binding = null
}

private fun readRawResourceFile(resourceId: Int): String? {
return try {
val inputStream = resources.openRawResource(resourceId)
val bufferedReader = BufferedReader(InputStreamReader(inputStream))
val stringBuilder = StringBuilder()
var line: String? = bufferedReader.readLine()
while (line != null) {
stringBuilder.append(line)
line = bufferedReader.readLine()
}
bufferedReader.close()
inputStream.close()
stringBuilder.toString()
} catch (e: Exception) {
Log.e("MainActivity", "Error reading raw resource file", e)
null
}
}

/** Interface for notifying the host. */
interface Callback {
/** Notifies listener of Custom flow redirect button click. */
fun handleCustomFlowRedirectClicked(redirectUrl: String)

/** Notifies listener of Enhanced Setup flow button click. */
fun handleEnhancedSetupFlowClicked()
}

companion object {
private const val TAG = "CUSTOM_FLOW"
private const val ARG_DEVICE_INFO = "device_info"
private const val DCL_CUSTOM_FLOW_URL_KEY = "commissioningCustomFlowUrl";
private const val DCL_API_ROOT_URL = "https://on.dcl.csa-iot.org/dcl/model/models";
private const val CUSTOM_FLOW_RETURN_URL = "mt://modelinfo";

@JvmStatic
fun newInstance(deviceInfo: CHIPDeviceInfo): CHIPLedgerDetailsFragment {
Expand Down
Loading

0 comments on commit 233d775

Please sign in to comment.