Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android] Update to new SubscribeAttribute API #13015

Merged
merged 1 commit into from
Dec 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import kotlinx.android.synthetic.main.on_off_client_fragment.view.readBtn
import kotlinx.android.synthetic.main.on_off_client_fragment.view.showSubscribeDialogBtn
import kotlinx.android.synthetic.main.on_off_client_fragment.view.toggleBtn
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch

class OnOffClientFragment : Fragment() {
Expand Down Expand Up @@ -108,7 +107,9 @@ class OnOffClientFragment : Fragment() {
minIntervalEd.text.toString().toInt(),
maxIntervalEd.text.toString().toInt()
)
dialog.dismiss()
requireActivity().runOnUiThread {
dialog.dismiss()
}
}
}
dialog.show()
Expand All @@ -117,26 +118,20 @@ class OnOffClientFragment : Fragment() {
private suspend fun sendSubscribeOnOffClick(minInterval: Int, maxInterval: Int) {
val onOffCluster = getOnOffClusterForDevice()

val subscribeCallback = object : ChipClusters.DefaultClusterCallback {
override fun onSuccess() {
val message = "Subscribe on/off success"
Log.v(TAG, message)
showMessage(message)

onOffCluster.reportOnOffAttribute(object : ChipClusters.BooleanAttributeCallback {
override fun onSuccess(on: Boolean) {
Log.v(TAG, "Report on/off attribute value: $on")
val subscribeCallback = object : ChipClusters.BooleanAttributeCallback {
override fun onSuccess(value: Boolean) {
val formatter = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
val time = formatter.format(Calendar.getInstance(Locale.getDefault()).time)
val message = "Subscribed on/off value at $time: ${if (value) "ON" else "OFF"}"

val formatter = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
val time = formatter.format(Calendar.getInstance(Locale.getDefault()).time)
showReportMessage("Report on/off at $time: ${if (on) "ON" else "OFF"}")
}
Log.v(TAG, message)
showReportMessage(message)
}

override fun onError(ex: Exception) {
Log.e(TAG, "Error reporting on/off attribute", ex)
showReportMessage("Error reporting on/off attribute: $ex")
}
})
override fun onSubscriptionEstablished() {
val message = "Subscription for on/off established"
Log.v(TAG, message)
showMessage(message)
}

override fun onError(ex: Exception) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,8 @@ import kotlinx.android.synthetic.main.sensor_client_fragment.clusterNameSpinner
import kotlinx.android.synthetic.main.sensor_client_fragment.deviceIdEd
import kotlinx.android.synthetic.main.sensor_client_fragment.endpointIdEd
import kotlinx.android.synthetic.main.sensor_client_fragment.lastValueTv
import kotlinx.android.synthetic.main.sensor_client_fragment.readSensorBtn
import kotlinx.android.synthetic.main.sensor_client_fragment.sensorGraph
import kotlinx.android.synthetic.main.sensor_client_fragment.view.clusterNameSpinner
import kotlinx.android.synthetic.main.sensor_client_fragment.view.readSensorBtn
import kotlinx.android.synthetic.main.sensor_client_fragment.view.sensorGraph
import kotlinx.android.synthetic.main.sensor_client_fragment.view.watchSensorBtn
import kotlinx.android.synthetic.main.sensor_client_fragment.watchSensorBtn
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
Expand All @@ -52,53 +49,56 @@ class SensorClientFragment : Fragment() {
savedInstanceState: Bundle?
): View {
scope = viewLifecycleOwner.lifecycleScope
return inflater.inflate(R.layout.sensor_client_fragment, container, false)
}

return inflater.inflate(R.layout.sensor_client_fragment, container, false).apply {
ChipClient.getDeviceController(requireContext()).setCompletionListener(null)
deviceIdEd.setOnEditorActionListener { textView, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
updateAddress(textView.text.toString())
resetSensorGraph() // reset the graph on device change
}
actionId == EditorInfo.IME_ACTION_DONE
}
endpointIdEd.setOnEditorActionListener { textView, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE)
resetSensorGraph() // reset the graph on endpoint change
actionId == EditorInfo.IME_ACTION_DONE
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

ChipClient.getDeviceController(requireContext()).setCompletionListener(null)
deviceIdEd.setOnEditorActionListener { textView, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
updateAddress(textView.text.toString())
resetSensorGraph() // reset the graph on device change
}
clusterNameSpinner.adapter = makeClusterNamesAdapter()
clusterNameSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) = Unit
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
resetSensorGraph() // reset the graph on cluster change
}
actionId == EditorInfo.IME_ACTION_DONE
}
endpointIdEd.setOnEditorActionListener { textView, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE)
resetSensorGraph() // reset the graph on endpoint change
actionId == EditorInfo.IME_ACTION_DONE
}
clusterNameSpinner.adapter = makeClusterNamesAdapter()
clusterNameSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) = Unit
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
resetSensorGraph() // reset the graph on cluster change
}
}

readSensorBtn.setOnClickListener { scope.launch { readSensorCluster() } }
watchSensorBtn.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
scope.launch { subscribeSensorCluster() }
} else {
unsubscribeSensorCluster()
}
readSensorBtn.setOnClickListener { scope.launch { readSensorCluster() } }
watchSensorBtn.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
scope.launch { subscribeSensorCluster() }
} else {
unsubscribeSensorCluster()
}
}

val currentTime = Calendar.getInstance().time.time
sensorGraph.addSeries(sensorData)
sensorGraph.viewport.isXAxisBoundsManual = true
sensorGraph.viewport.setMinX(currentTime.toDouble())
sensorGraph.viewport.setMaxX(currentTime.toDouble() + MIN_REFRESH_PERIOD_S * 1000 * MAX_DATA_POINTS)
sensorGraph.gridLabelRenderer.padding = 20
sensorGraph.gridLabelRenderer.numHorizontalLabels = 4
sensorGraph.gridLabelRenderer.setHorizontalLabelsAngle(150)
sensorGraph.gridLabelRenderer.labelFormatter = object : LabelFormatter {
override fun setViewport(viewport: Viewport?) = Unit
override fun formatLabel(value: Double, isValueX: Boolean): String {
if (!isValueX)
return "%.2f".format(value)
return SimpleDateFormat("H:mm:ss").format(Date(value.toLong())).toString()
}
val currentTime = Calendar.getInstance().time.time
sensorGraph.addSeries(sensorData)
sensorGraph.viewport.isXAxisBoundsManual = true
sensorGraph.viewport.setMinX(currentTime.toDouble())
sensorGraph.viewport.setMaxX(currentTime.toDouble() + MIN_REFRESH_PERIOD_S * 1000 * MAX_DATA_POINTS)
sensorGraph.gridLabelRenderer.padding = 20
sensorGraph.gridLabelRenderer.numHorizontalLabels = 4
sensorGraph.gridLabelRenderer.setHorizontalLabelsAngle(150)
sensorGraph.gridLabelRenderer.labelFormatter = object : LabelFormatter {
override fun setViewport(viewport: Viewport?) = Unit
override fun formatLabel(value: Double, isValueX: Boolean): String {
if (!isValueX)
return "%.2f".format(value)
return SimpleDateFormat("H:mm:ss").format(Date(value.toLong())).toString()
}
}
}
Expand Down Expand Up @@ -243,13 +243,9 @@ class SensorClientFragment : Fragment() {
},
"subscribe" to { device: Long, endpointId: Int, callback: ReadCallback ->
val cluster = ChipClusters.TemperatureMeasurementCluster(device, endpointId)
cluster.reportMeasuredValueAttribute(callback)
cluster.subscribeMeasuredValueAttribute(object : ChipClusters.DefaultClusterCallback {
override fun onSuccess() = Unit
override fun onError(ex: Exception) {
callback.onError(ex)
}
}, MIN_REFRESH_PERIOD_S, MAX_REFRESH_PERIOD_S)
cluster.subscribeMeasuredValueAttribute(callback,
MIN_REFRESH_PERIOD_S,
MAX_REFRESH_PERIOD_S)
},
"unitValue" to 0.01,
"unitSymbol" to "\u00B0C"
Expand All @@ -261,13 +257,9 @@ class SensorClientFragment : Fragment() {
},
"subscribe" to { device: Long, endpointId: Int, callback: ReadCallback ->
val cluster = ChipClusters.PressureMeasurementCluster(device, endpointId)
cluster.reportMeasuredValueAttribute(callback)
cluster.subscribeMeasuredValueAttribute(object : ChipClusters.DefaultClusterCallback {
override fun onSuccess() = Unit
override fun onError(ex: Exception) {
callback.onError(ex)
}
}, MIN_REFRESH_PERIOD_S, MAX_REFRESH_PERIOD_S)
cluster.subscribeMeasuredValueAttribute(callback,
MIN_REFRESH_PERIOD_S,
MAX_REFRESH_PERIOD_S)
},
"unitValue" to 1.0,
"unitSymbol" to "hPa"
Expand All @@ -279,13 +271,9 @@ class SensorClientFragment : Fragment() {
},
"subscribe" to { device: Long, endpointId: Int, callback: ReadCallback ->
val cluster = ChipClusters.RelativeHumidityMeasurementCluster(device, endpointId)
cluster.reportMeasuredValueAttribute(callback)
cluster.subscribeMeasuredValueAttribute(object : ChipClusters.DefaultClusterCallback {
override fun onSuccess() = Unit
override fun onError(ex: Exception) {
callback.onError(ex)
}
}, MIN_REFRESH_PERIOD_S, MAX_REFRESH_PERIOD_S)
cluster.subscribeMeasuredValueAttribute(callback,
MIN_REFRESH_PERIOD_S,
MAX_REFRESH_PERIOD_S)
},
"unitValue" to 0.01,
"unitSymbol" to "%"
Expand Down
35 changes: 16 additions & 19 deletions src/controller/java/templates/CHIPClusters-JNI.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <zap-generated/CHIPClusters.h>
#include <zap-generated/CHIPClientCallbacks.h>

#include <controller/java/AndroidCallbacks.h>
#include <controller/java/AndroidClusterExceptions.h>
#include <controller/java/CHIPDefaultCallbacks.h>
#include <lib/support/JniReferences.h>
Expand Down Expand Up @@ -125,38 +126,34 @@ JNI_METHOD(void, {{asUpperCamelCase ../name}}Cluster, write{{asUpperCamelCase na
JNI_METHOD(void, {{asCamelCased ../name false}}Cluster, subscribe{{asCamelCased name false}}Attribute)(JNIEnv * env, jobject self, jlong clusterPtr, jobject callback, jint minInterval, jint maxInterval)
{
chip::DeviceLayer::StackLock lock;
std::unique_ptr<CHIPDefaultSuccessCallback, void (*)(CHIPDefaultSuccessCallback *)> onSuccess(Platform::New<CHIPDefaultSuccessCallback>(callback), Platform::Delete<CHIPDefaultSuccessCallback>);
{{~#*inline "callbackName"~}}
{{~#if_in_global_responses~}}
CHIP{{chipCallback.name}}AttributeCallback
{{~else~}}
CHIP{{asCamelCased parent.name false}}{{asCamelCased name false}}AttributeCallback
{{~/if_in_global_responses~}}
{{~/inline}}

std::unique_ptr<{{>callbackName}}, void (*)({{>callbackName}} *)> onSuccess(Platform::New<{{>callbackName}}>(callback, true), chip::Platform::Delete<{{>callbackName}}>);
VerifyOrReturn(onSuccess.get() != nullptr, chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error creating native success callback", CHIP_ERROR_NO_MEMORY));

std::unique_ptr<CHIPDefaultFailureCallback, void (*)(CHIPDefaultFailureCallback *)> onFailure(Platform::New<CHIPDefaultFailureCallback>(callback), Platform::Delete<CHIPDefaultFailureCallback>);
std::unique_ptr<CHIPDefaultFailureCallback, void (*)(CHIPDefaultFailureCallback *)> onFailure(Platform::New<CHIPDefaultFailureCallback>(callback), chip::Platform::Delete<CHIPDefaultFailureCallback>);
VerifyOrReturn(onFailure.get() != nullptr, chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error creating native failure callback", CHIP_ERROR_NO_MEMORY));

CHIP_ERROR err = CHIP_NO_ERROR;
{{asCamelCased ../name false}}Cluster * cppCluster = reinterpret_cast<{{asCamelCased ../name false}}Cluster *>(clusterPtr);
VerifyOrReturn(cppCluster != nullptr, chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Could not get native cluster", CHIP_ERROR_INCORRECT_STATE));

err = cppCluster->SubscribeAttribute{{asCamelCased name false}}(onSuccess->Cancel(), onFailure->Cancel(), static_cast<uint16_t>(minInterval), static_cast<uint16_t>(maxInterval));
using TypeInfo = chip::app::Clusters::{{asUpperCamelCase parent.name}}::Attributes::{{asUpperCamelCase name}}::TypeInfo;
auto successFn = chip::Callback::Callback<CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}AttributeCallbackType>::FromCancelable(onSuccess->Cancel());
auto failureFn = chip::Callback::Callback<CHIPDefaultFailureCallbackType>::FromCancelable(onFailure->Cancel());

err = cppCluster->SubscribeAttribute<TypeInfo>(onSuccess->mContext, successFn->mCall, failureFn->mCall, static_cast<uint16_t>(minInterval), static_cast<uint16_t>(maxInterval), {{>callbackName}}::OnSubscriptionEstablished);
VerifyOrReturn(err == CHIP_NO_ERROR, chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error subscribing to attribute", err));

onSuccess.release();
onFailure.release();
}

JNI_METHOD(void, {{asCamelCased ../name false}}Cluster, report{{asCamelCased name false}}Attribute)(JNIEnv * env, jobject self, jlong clusterPtr, jobject callback)
{
chip::DeviceLayer::StackLock lock;
std::unique_ptr<CHIP{{chipCallback.name}}AttributeCallback, void (*)(CHIP{{chipCallback.name}}AttributeCallback *)> onReport(Platform::New<CHIP{{chipCallback.name}}AttributeCallback>(callback, true), Platform::Delete<CHIP{{chipCallback.name}}AttributeCallback>);
VerifyOrReturn(onReport.get() != nullptr, chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error creating native report callback", CHIP_ERROR_NO_MEMORY));

CHIP_ERROR err = CHIP_NO_ERROR;
{{asCamelCased ../name false}}Cluster * cppCluster = reinterpret_cast<{{asCamelCased ../name false}}Cluster *>(clusterPtr);
VerifyOrReturn(cppCluster != nullptr, chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Could not get native cluster", CHIP_ERROR_INCORRECT_STATE));

err = cppCluster->ReportAttribute{{asCamelCased name false}}(onReport->Cancel());
VerifyOrReturn(err == CHIP_NO_ERROR, chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error registering for attribute reporting", err));

onReport.release();
}
{{/unless}}
{{/if}}
{{/unless}}
Expand Down
2 changes: 1 addition & 1 deletion src/controller/java/templates/CHIPReadCallbacks-src.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

#include <zap-generated/CHIPClientCallbacks.h>

#include <jni.h>
#include <lib/support/JniReferences.h>
#include <lib/support/JniTypeWrappers.h>
#include <jni.h>
#include <lib/support/CodeUtils.h>
#include <platform/PlatformManager.h>

Expand Down
11 changes: 11 additions & 0 deletions src/controller/java/templates/CHIPReadCallbacks.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
{{#if (chip_has_client_clusters)}}
#include "CHIPCallbackTypes.h"

#include <controller/java/AndroidCallbacks.h>
#include <jni.h>
#include <lib/support/ErrorStr.h>
#include <lib/support/JniReferences.h>
#include <zap-generated/CHIPClientCallbacks.h>

{{#chip_server_global_responses}}
Expand All @@ -21,6 +24,10 @@ public:
}

static void CallbackFn(void * context, {{chipCallback.type}} value);
static void OnSubscriptionEstablished(void * context) {
CHIP_ERROR err = chip::JniReferences::GetInstance().CallSubscriptionEstablished(reinterpret_cast<CHIP{{chipCallback.name}}AttributeCallback *>(context)->javaCallbackRef);
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Zcl, "Error calling onSubscriptionEstablished: %s", ErrorStr(err)));
};

private:
jobject javaCallbackRef;
Expand Down Expand Up @@ -49,6 +56,10 @@ public:
}

static void CallbackFn(void * context, {{zapTypeToDecodableClusterObjectType type ns=parent.name isArgument=true}} {{#if isList}}list{{else}}value{{/if}});
static void OnSubscriptionEstablished(void * context) {
CHIP_ERROR err = chip::JniReferences::GetInstance().CallSubscriptionEstablished(reinterpret_cast<CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback *>(context)->javaCallbackRef);
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Zcl, "Error calling onSubscriptionEstablished: %s", ErrorStr(err)));
};

private:
jobject javaCallbackRef;
Expand Down
Loading