diff --git a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/ChipClient.kt b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/ChipClient.kt index 044b6fdd5a25d4..c3c42e76463aea 100644 --- a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/ChipClient.kt +++ b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/ChipClient.kt @@ -17,11 +17,17 @@ */ package com.google.chip.chiptool +import android.util.Log import chip.devicecontroller.ChipDeviceController +import chip.devicecontroller.GetConnectedDeviceCallbackJni.GetConnectedDeviceCallback +import java.lang.IllegalStateException +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException +import kotlin.coroutines.suspendCoroutine /** Lazily instantiates [ChipDeviceController] and holds a reference to it. */ object ChipClient { - + private const val TAG = "ChipClient" private lateinit var chipDeviceController: ChipDeviceController fun getDeviceController(): ChipDeviceController { @@ -30,4 +36,26 @@ object ChipClient { } return chipDeviceController } + + /** + * Wrapper around [ChipDeviceController.getConnectedDevicePointer] to return the value directly. + */ + suspend fun getConnectedDevicePointer(nodeId: Long): Long { + return suspendCoroutine { continuation -> + getDeviceController().getConnectedDevicePointer( + nodeId, + object : GetConnectedDeviceCallback { + override fun onDeviceConnected(devicePointer: Long) { + Log.d(TAG, "Got connected device pointer") + continuation.resume(devicePointer) + } + + override fun onConnectionFailure(nodeId: Long, error: Exception) { + val errorMessage = "Unable to get connected device with nodeId $nodeId" + Log.e(TAG, errorMessage, error) + continuation.resumeWithException(IllegalStateException(errorMessage)) + } + }) + } + } } diff --git a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/GenericChipDeviceListener.kt b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/GenericChipDeviceListener.kt index 2b8d465d1c4f3a..9a5036cbd39214 100644 --- a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/GenericChipDeviceListener.kt +++ b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/GenericChipDeviceListener.kt @@ -23,6 +23,10 @@ open class GenericChipDeviceListener : ChipDeviceController.CompletionListener { // No op } + override fun onCommissioningComplete(nodeId: Long, errorCode: Int) { + // No op + } + override fun onNetworkCommissioningComplete(code: Int) { // No op } diff --git a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OnOffClientFragment.kt b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OnOffClientFragment.kt index fb610c816e0bbd..2534b9f47567aa 100644 --- a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OnOffClientFragment.kt +++ b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OnOffClientFragment.kt @@ -26,11 +26,18 @@ import kotlinx.android.synthetic.main.on_off_client_fragment.view.onBtn import kotlinx.android.synthetic.main.on_off_client_fragment.view.readBtn import kotlinx.android.synthetic.main.on_off_client_fragment.view.toggleBtn import kotlinx.android.synthetic.main.on_off_client_fragment.view.updateAddressBtn +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch class OnOffClientFragment : Fragment() { private val deviceController: ChipDeviceController get() = ChipClient.getDeviceController() + private val scope = CoroutineScope(Dispatchers.Main + Job()) + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -40,9 +47,10 @@ class OnOffClientFragment : Fragment() { deviceController.setCompletionListener(ChipControllerCallback()) updateAddressBtn.setOnClickListener { updateAddressClick() } - onBtn.setOnClickListener { sendOnCommandClick() } - offBtn.setOnClickListener { sendOffCommandClick() } - toggleBtn.setOnClickListener { sendToggleCommandClick() } + onBtn.setOnClickListener { scope.launch { sendOnCommandClick() } } + offBtn.setOnClickListener { scope.launch { sendOffCommandClick() } } + toggleBtn.setOnClickListener { scope.launch { sendToggleCommandClick() } } + readBtn.setOnClickListener { scope.launch { sendReadOnOffClick() } } levelBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) { @@ -58,14 +66,13 @@ class OnOffClientFragment : Fragment() { "Level is: " + levelBar.progress, Toast.LENGTH_SHORT ).show() - sendLevelCommandClick() + scope.launch { sendLevelCommandClick() } } }) - readBtn.setOnClickListener { sendReadOnOffClick() } } } - private fun sendReadOnOffClick() { + private suspend fun sendReadOnOffClick() { getOnOffClusterForDevice().readOnOffAttribute(object : ChipClusters.BooleanAttributeCallback { override fun onSuccess(on: Boolean) { Log.v(TAG, "On/Off attribute value: $on") @@ -89,6 +96,10 @@ class OnOffClientFragment : Fragment() { inner class ChipControllerCallback : GenericChipDeviceListener() { override fun onConnectDeviceComplete() {} + override fun onCommissioningComplete(nodeId: Long, errorCode: Int) { + Log.d(TAG, "onCommissioningComplete for nodeId $nodeId: $errorCode") + } + override fun onSendMessageComplete(message: String?) { commandStatusTv.text = requireContext().getString(R.string.echo_status_response, message) } @@ -106,6 +117,11 @@ class OnOffClientFragment : Fragment() { } } + override fun onStop() { + super.onStop() + scope.cancel() + } + private fun updateAddressClick() { try{ deviceController.updateDevice( @@ -118,10 +134,9 @@ class OnOffClientFragment : Fragment() { } } - private fun sendLevelCommandClick() { + private suspend fun sendLevelCommandClick() { val cluster = ChipClusters.LevelControlCluster( - ChipClient.getDeviceController() - .getDevicePointer(deviceIdEd.text.toString().toLong()), 1 + ChipClient.getConnectedDevicePointer(deviceIdEd.text.toString().toLong()), 1 ) cluster.moveToLevel(object : ChipClusters.DefaultClusterCallback { override fun onSuccess() { @@ -136,7 +151,7 @@ class OnOffClientFragment : Fragment() { }, levelBar.progress, 0, 0, 0) } - private fun sendOnCommandClick() { + private suspend fun sendOnCommandClick() { getOnOffClusterForDevice().on(object : ChipClusters.DefaultClusterCallback { override fun onSuccess() { showMessage("ON command success") @@ -150,7 +165,7 @@ class OnOffClientFragment : Fragment() { }) } - private fun sendOffCommandClick() { + private suspend fun sendOffCommandClick() { getOnOffClusterForDevice().off(object : ChipClusters.DefaultClusterCallback { override fun onSuccess() { showMessage("OFF command success") @@ -163,7 +178,7 @@ class OnOffClientFragment : Fragment() { }) } - private fun sendToggleCommandClick() { + private suspend fun sendToggleCommandClick() { getOnOffClusterForDevice().toggle(object : ChipClusters.DefaultClusterCallback { override fun onSuccess() { showMessage("TOGGLE command success") @@ -176,10 +191,9 @@ class OnOffClientFragment : Fragment() { }) } - private fun getOnOffClusterForDevice(): OnOffCluster { + private suspend fun getOnOffClusterForDevice(): OnOffCluster { return OnOffCluster( - ChipClient.getDeviceController() - .getDevicePointer(deviceIdEd.text.toString().toLong()), 1 + ChipClient.getConnectedDevicePointer(deviceIdEd.text.toString().toLong()), 1 ) } diff --git a/src/controller/java/AndroidCallbacks-JNI.cpp b/src/controller/java/AndroidCallbacks-JNI.cpp new file mode 100644 index 00000000000000..7d511e49cb5d82 --- /dev/null +++ b/src/controller/java/AndroidCallbacks-JNI.cpp @@ -0,0 +1,39 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "AndroidCallbacks.h" + +#include +#include +#include + +#define JNI_METHOD(RETURN, CLASS_NAME, METHOD_NAME) \ + extern "C" JNIEXPORT RETURN JNICALL Java_chip_devicecontroller_##CLASS_NAME##_##METHOD_NAME + +using namespace chip::Controller; + +JNI_METHOD(jlong, GetConnectedDeviceCallbackJni, newCallback)(JNIEnv * env, jobject self, jobject callback) +{ + GetConnectedDeviceCallback * connectedDeviceCallback = new GetConnectedDeviceCallback(callback); + return reinterpret_cast(connectedDeviceCallback); +} + +JNI_METHOD(void, GetConnectedDeviceCallbackJni, deleteCallback)(JNIEnv * env, jobject self, jlong callbackHandle) +{ + GetConnectedDeviceCallback * connectedDeviceCallback = reinterpret_cast(callbackHandle); + VerifyOrReturn(connectedDeviceCallback != nullptr, ChipLogError(Controller, "GetConnectedDeviceCallback handle is nullptr")); + delete connectedDeviceCallback; +} diff --git a/src/controller/java/AndroidCallbacks.cpp b/src/controller/java/AndroidCallbacks.cpp new file mode 100644 index 00000000000000..d60f39c289e3fc --- /dev/null +++ b/src/controller/java/AndroidCallbacks.cpp @@ -0,0 +1,96 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "AndroidCallbacks.h" +#include "JniReferences.h" +#include "JniTypeWrappers.h" + +#include +#include +#include +#include + +using namespace chip::Controller; + +GetConnectedDeviceCallback::GetConnectedDeviceCallback(jobject javaCallback) : + mOnSuccess(OnDeviceConnectedFn, this), mOnFailure(OnDeviceConnectionFailureFn, this) +{ + JNIEnv * env = chip::Controller::JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread")); + mJavaCallbackRef = env->NewGlobalRef(javaCallback); + if (mJavaCallbackRef == nullptr) + { + ChipLogError(Controller, "Could not create global reference for Java callback"); + } +} + +GetConnectedDeviceCallback::~GetConnectedDeviceCallback() +{ + JNIEnv * env = chip::Controller::JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread")); + env->DeleteGlobalRef(mJavaCallbackRef); +} + +void GetConnectedDeviceCallback::OnDeviceConnectedFn(void * context, Device * device) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + auto * self = static_cast(context); + jobject javaCallback = self->mJavaCallbackRef; + + jclass getConnectedDeviceCallbackCls = nullptr; + JniReferences::GetInstance().GetClassRef(env, "chip/devicecontroller/GetConnectedDeviceCallbackJni$GetConnectedDeviceCallback", + getConnectedDeviceCallbackCls); + VerifyOrReturn(getConnectedDeviceCallbackCls != nullptr, + ChipLogError(Controller, "Could not find GetConnectedDeviceCallback class")); + JniClass getConnectedDeviceCallbackJniCls(getConnectedDeviceCallbackCls); + + jmethodID successMethod; + JniReferences::GetInstance().FindMethod(env, javaCallback, "onDeviceConnected", "(J)V", &successMethod); + VerifyOrReturn(successMethod != nullptr, ChipLogError(Controller, "Could not find onDeviceConnected method")); + + static_assert(sizeof(jlong) >= sizeof(void *), "Need to store a pointer in a Java handle"); + env->CallVoidMethod(javaCallback, successMethod, reinterpret_cast(device)); +} + +void GetConnectedDeviceCallback::OnDeviceConnectionFailureFn(void * context, NodeId nodeId, CHIP_ERROR error) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + auto * self = static_cast(context); + jobject javaCallback = self->mJavaCallbackRef; + + jclass getConnectedDeviceCallbackCls = nullptr; + JniReferences::GetInstance().GetClassRef(env, "chip/devicecontroller/GetConnectedDeviceCallbackJni$GetConnectedDeviceCallback", + getConnectedDeviceCallbackCls); + VerifyOrReturn(getConnectedDeviceCallbackCls != nullptr, + ChipLogError(Controller, "Could not find GetConnectedDeviceCallback class")); + JniClass getConnectedDeviceCallbackJniCls(getConnectedDeviceCallbackCls); + + jmethodID failureMethod; + JniReferences::GetInstance().FindMethod(env, javaCallback, "onConnectionFailure", "(JLjava/lang/Exception;)V", &failureMethod); + VerifyOrReturn(failureMethod != nullptr, ChipLogError(Controller, "Could not find onConnectionFailure method")); + + // Create the exception to return. + jclass controllerExceptionCls; + CHIP_ERROR err = JniReferences::GetInstance().GetClassRef(env, "chip/devicecontroller/ChipDeviceControllerException", + controllerExceptionCls); + VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Could not find exception type for onConnectionFailure")); + JniClass controllerExceptionJniCls(controllerExceptionCls); + + jmethodID exceptionConstructor = env->GetMethodID(controllerExceptionCls, "", "(ILjava/lang/String;)V"); + jobject exception = env->NewObject(controllerExceptionCls, exceptionConstructor, error, env->NewStringUTF(ErrorStr(error))); + + env->CallVoidMethod(javaCallback, failureMethod, nodeId, exception); +} diff --git a/src/controller/java/AndroidCallbacks.h b/src/controller/java/AndroidCallbacks.h new file mode 100644 index 00000000000000..0b82e0117f65c8 --- /dev/null +++ b/src/controller/java/AndroidCallbacks.h @@ -0,0 +1,40 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include + +namespace chip { +namespace Controller { + +// Callback for success and failure cases of GetConnectedDevice(). +struct GetConnectedDeviceCallback +{ + GetConnectedDeviceCallback(jobject javaCallback); + ~GetConnectedDeviceCallback(); + + static void OnDeviceConnectedFn(void * context, Device * device); + static void OnDeviceConnectionFailureFn(void * context, NodeId nodeId, CHIP_ERROR error); + + Callback::Callback mOnSuccess; + Callback::Callback mOnFailure; + jobject mJavaCallbackRef; +}; + +} // namespace Controller +} // namespace chip diff --git a/src/controller/java/AndroidDeviceControllerWrapper.cpp b/src/controller/java/AndroidDeviceControllerWrapper.cpp index 06d2dc168f3fb5..ea46b532e643ae 100644 --- a/src/controller/java/AndroidDeviceControllerWrapper.cpp +++ b/src/controller/java/AndroidDeviceControllerWrapper.cpp @@ -151,6 +151,17 @@ void AndroidDeviceControllerWrapper::OnPairingDeleted(CHIP_ERROR error) CallJavaMethod("onPairingDeleted", static_cast(error)); } +void AndroidDeviceControllerWrapper::OnCommissioningComplete(NodeId deviceId, CHIP_ERROR error) +{ + StackUnlockGuard unlockGuard(mStackLock); + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + jmethodID onCommissioningCompleteMethod; + CHIP_ERROR err = JniReferences::GetInstance().FindMethod(env, mJavaObjectRef, "onCommissioningComplete", "(JI)V", + &onCommissioningCompleteMethod); + VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Error finding Java method: %d", err)); + env->CallVoidMethod(mJavaObjectRef, onCommissioningCompleteMethod, static_cast(deviceId), error); +} + // TODO Refactor this API to match latest spec, so that GenerateNodeOperationalCertificate receives the full CSR Elements data // payload. CHIP_ERROR diff --git a/src/controller/java/AndroidDeviceControllerWrapper.h b/src/controller/java/AndroidDeviceControllerWrapper.h index 1f0913ee4300e5..14eb8da123f2f1 100644 --- a/src/controller/java/AndroidDeviceControllerWrapper.h +++ b/src/controller/java/AndroidDeviceControllerWrapper.h @@ -55,6 +55,7 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel void OnStatusUpdate(chip::Controller::DevicePairingDelegate::Status status) override; void OnPairingComplete(CHIP_ERROR error) override; void OnPairingDeleted(CHIP_ERROR error) override; + void OnCommissioningComplete(chip::NodeId deviceId, CHIP_ERROR error) override; // OperationalCredentialsDelegate implementation CHIP_ERROR @@ -87,7 +88,7 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel chip::Crypto::P256Keypair mIssuer; bool mInitialized = false; uint32_t mIssuerId = 0; - uint32_t mNow = chip::CalendarToChipEpochTime(2021, 06, 10, 0, 0, 0, mNow); + uint32_t mNow = 0; uint32_t mValidity = 10 * chip::kSecondsPerStandardYear; ChipDeviceControllerPtr mController; @@ -102,7 +103,9 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel AndroidDeviceControllerWrapper(ChipDeviceControllerPtr controller, pthread_mutex_t * stackLock) : mController(std::move(controller)), mStackLock(stackLock) - {} + { + chip::CalendarToChipEpochTime(2021, 06, 10, 0, 0, 0, mNow); + } }; inline jlong AndroidDeviceControllerWrapper::ToJNIHandle() diff --git a/src/controller/java/BUILD.gn b/src/controller/java/BUILD.gn index 07aa9209f91598..7b54e0bfbb7d80 100644 --- a/src/controller/java/BUILD.gn +++ b/src/controller/java/BUILD.gn @@ -28,6 +28,9 @@ shared_library("jni") { "AndroidBleConnectionDelegate.h", "AndroidBlePlatformDelegate.cpp", "AndroidBlePlatformDelegate.h", + "AndroidCallbacks-JNI.cpp", + "AndroidCallbacks.cpp", + "AndroidCallbacks.h", "AndroidDeviceControllerWrapper.cpp", "AndroidDeviceControllerWrapper.h", "AndroidKeyValueStoreManagerImpl.cpp", @@ -68,6 +71,7 @@ android_library("java") { "src/chip/devicecontroller/ChipCommandType.java", "src/chip/devicecontroller/ChipDeviceController.java", "src/chip/devicecontroller/ChipDeviceControllerException.java", + "src/chip/devicecontroller/GetConnectedDeviceCallbackJni.java", "src/chip/devicecontroller/KeyValueStoreManager.java", "src/chip/devicecontroller/NsdManagerServiceResolver.java", "src/chip/devicecontroller/PreferencesKeyValueStoreManager.java", diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp index fcb04e84e38d7f..5078b9046e656f 100644 --- a/src/controller/java/CHIPDeviceController-JNI.cpp +++ b/src/controller/java/CHIPDeviceController-JNI.cpp @@ -25,6 +25,7 @@ #include "AndroidBleApplicationDelegate.h" #include "AndroidBleConnectionDelegate.h" #include "AndroidBlePlatformDelegate.h" +#include "AndroidCallbacks.h" #include "AndroidDeviceControllerWrapper.h" #include "CHIPJNIError.h" #include "JniReferences.h" @@ -350,10 +351,20 @@ JNI_METHOD(jlong, getDevicePointer)(JNIEnv * env, jobject self, jlong handle, jl GetCHIPDevice(env, handle, deviceId, &chipDevice); - static_assert(sizeof(jlong) >= sizeof(void *), "Need to store a pointer in a java handle"); + static_assert(sizeof(jlong) >= sizeof(void *), "Need to store a pointer in a Java handle"); return reinterpret_cast(chipDevice); } +JNI_METHOD(void, getConnectedDevicePointer)(JNIEnv * env, jobject self, jlong handle, jlong nodeId, jlong callbackHandle) +{ + StackLockGuard lock(JniReferences::GetInstance().GetStackLock()); + AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); + + GetConnectedDeviceCallback * connectedDeviceCallback = reinterpret_cast(callbackHandle); + VerifyOrReturn(connectedDeviceCallback != nullptr, ChipLogError(Controller, "GetConnectedDeviceCallback handle is nullptr")); + wrapper->Controller()->GetConnectedDevice(nodeId, &connectedDeviceCallback->mOnSuccess, &connectedDeviceCallback->mOnFailure); +} + JNI_METHOD(void, pairTestDeviceWithoutSecurity)(JNIEnv * env, jobject self, jlong handle, jstring deviceAddr) { StackLockGuard lock(JniReferences::GetInstance().GetStackLock()); diff --git a/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java b/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java index f7c18e4df9ddb2..7253d994376764 100644 --- a/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java +++ b/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java @@ -20,6 +20,7 @@ import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; import android.util.Log; +import chip.devicecontroller.GetConnectedDeviceCallbackJni.GetConnectedDeviceCallback; /** Controller to interact with the CHIP device. */ public class ChipDeviceController { @@ -90,8 +91,21 @@ public void pairTestDeviceWithoutSecurity(String ipAddress) { pairTestDeviceWithoutSecurity(deviceControllerPtr, ipAddress); } - public long getDevicePointer(long deviceId) { - return getDevicePointer(deviceControllerPtr, deviceId); + /** + * Returns a pointer to a device with the specified nodeId. The device is not guaranteed to be + * connected. + * + *

TODO(#8443): This method and getConnectedDevicePointer() could benefit from ChipDevice + * abstraction to hide the pointer passing. + */ + public long getDevicePointer(long nodeId) { + return getDevicePointer(deviceControllerPtr, nodeId); + } + + /** Through GetConnectedDeviceCallback, returns a pointer to a connected device or an error. */ + public void getConnectedDevicePointer(long nodeId, GetConnectedDeviceCallback callback) { + GetConnectedDeviceCallbackJni jniCallback = new GetConnectedDeviceCallbackJni(callback); + getConnectedDevicePointer(deviceControllerPtr, nodeId, jniCallback.getCallbackHandle()); } public boolean disconnectDevice(long deviceId) { @@ -118,6 +132,12 @@ public void onPairingComplete(int errorCode) { } } + public void onCommissioningComplete(long nodeId, int errorCode) { + if (completionListener != null) { + completionListener.onCommissioningComplete(nodeId, errorCode); + } + } + public void onOpCSRGenerationComplete(byte[] csr) { if (completionListener != null) { completionListener.onOpCSRGenerationComplete(csr); @@ -217,6 +237,9 @@ private native void pairDevice( private native long getDevicePointer(long deviceControllerPtr, long deviceId); + private native void getConnectedDevicePointer( + long deviceControllerPtr, long deviceId, long callbackHandle); + private native void pairTestDeviceWithoutSecurity(long deviceControllerPtr, String ipAddress); private native boolean disconnectDevice(long deviceControllerPtr, long deviceId); @@ -283,6 +306,9 @@ public interface CompletionListener { /** Notifies the deletion of pairing session. */ void onPairingDeleted(int errorCode); + /** Notifies the completion of commissioning. */ + void onCommissioningComplete(long nodeId, int errorCode); + /** Notifies the completion of network commissioning */ void onNetworkCommissioningComplete(int errorCode); diff --git a/src/controller/java/src/chip/devicecontroller/GetConnectedDeviceCallbackJni.java b/src/controller/java/src/chip/devicecontroller/GetConnectedDeviceCallbackJni.java new file mode 100644 index 00000000000000..8820cabe69eb73 --- /dev/null +++ b/src/controller/java/src/chip/devicecontroller/GetConnectedDeviceCallbackJni.java @@ -0,0 +1,38 @@ +package chip.devicecontroller; + +/** JNI wrapper callback class for getting a connected device. */ +public class GetConnectedDeviceCallbackJni { + private GetConnectedDeviceCallback wrappedCallback; + private long callbackHandle; + + public GetConnectedDeviceCallbackJni(GetConnectedDeviceCallback wrappedCallback) { + this.wrappedCallback = wrappedCallback; + this.callbackHandle = newCallback(wrappedCallback); + } + + long getCallbackHandle() { + return callbackHandle; + } + + private native long newCallback(GetConnectedDeviceCallback wrappedCallback); + + private native void deleteCallback(long callbackHandle); + + // TODO(#8578): Replace finalizer with PhantomReference. + @SuppressWarnings("deprecation") + protected void finalize() throws Throwable { + super.finalize(); + + if (callbackHandle != 0) { + deleteCallback(callbackHandle); + callbackHandle = 0; + } + } + + /** Callbacks for getting a device connected with PASE or CASE, depending on the context. */ + public interface GetConnectedDeviceCallback { + void onDeviceConnected(long devicePointer); + + void onConnectionFailure(long nodeId, Exception error); + } +}