diff --git a/src/android/CHIPTest/gradle.properties b/src/android/CHIPTest/gradle.properties index d5dcc9461e28f2..3026069c70e98f 100644 --- a/src/android/CHIPTest/gradle.properties +++ b/src/android/CHIPTest/gradle.properties @@ -21,10 +21,10 @@ kotlin.code.style=official # Build SDK from source code and debug in Android Stduio. Must also set matterBuildSrcDir. matterSdkSourceBuild=false -# Point to the SDK build dir without quotes (../../../../out/android-arm64-chip-test for +# Point to the SDK build dir without quotes (out/android-arm64-chip-test for # example) to build SDK from source code and debug in Android Studio. # Set to blank to use the SDK prebuilt by scripts/build/build_examples.py. -matterBuildSrcDir=../../../../out/android-arm64-chip-test +matterBuildSrcDir=out/android-arm64-chip-test # Test libs to run matterUTestLib=libPlatformTests.a diff --git a/src/platform/android/DnssdImpl.cpp b/src/platform/android/DnssdImpl.cpp index 27f3fa26203ed8..8d5b5c4e2c81d2 100644 --- a/src/platform/android/DnssdImpl.cpp +++ b/src/platform/android/DnssdImpl.cpp @@ -17,6 +17,7 @@ #include "DnssdImpl.h" +#include #include #include #include @@ -36,9 +37,11 @@ namespace Dnssd { using namespace chip::Platform; namespace { -jobject sResolverObject = nullptr; -jobject sMdnsCallbackObject = nullptr; -jmethodID sResolveMethod = nullptr; +jobject sResolverObject = nullptr; +jobject sMdnsCallbackObject = nullptr; +jmethodID sResolveMethod = nullptr; +jmethodID sPublishMethod = nullptr; +jmethodID sRemoveServicesMethod = nullptr; } // namespace // Implemention of functions declared in lib/dnssd/platform/Dnssd.h @@ -59,17 +62,75 @@ CHIP_ERROR ChipDnssdShutdown() CHIP_ERROR ChipDnssdRemoveServices() { - return CHIP_ERROR_NOT_IMPLEMENTED; + VerifyOrReturnError(sResolverObject != nullptr && sRemoveServicesMethod != nullptr, CHIP_ERROR_INCORRECT_STATE); + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + env->CallVoidMethod(sResolverObject, sRemoveServicesMethod); + + if (env->ExceptionCheck()) + { + ChipLogError(Discovery, "Java exception in ChipDnssdRemoveServices"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return CHIP_JNI_ERROR_EXCEPTION_THROWN; + } + + return CHIP_NO_ERROR; } CHIP_ERROR ChipDnssdPublishService(const DnssdService * service) { - return CHIP_ERROR_NOT_IMPLEMENTED; + VerifyOrReturnError(service != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(sResolverObject != nullptr && sPublishMethod != nullptr, CHIP_ERROR_INCORRECT_STATE); + + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + UtfString jniName(env, service->mName); + UtfString jniHostName(env, service->mHostName); + + std::string serviceType = service->mType; + serviceType += '.'; + serviceType += (service->mProtocol == DnssdServiceProtocol::kDnssdProtocolUdp ? "_udp" : "_tcp"); + UtfString jniServiceType(env, serviceType.c_str()); + + jclass stringClass = env->FindClass("java/lang/String"); + jobjectArray keys = env->NewObjectArray(service->mTextEntrySize, stringClass, nullptr); + + jclass arrayElemType = env->FindClass("[B"); + jobjectArray datas = env->NewObjectArray(service->mTextEntrySize, arrayElemType, nullptr); + + for (size_t i = 0; i < service->mTextEntrySize; i++) + { + UtfString jniKey(env, service->mTextEntries[i].mKey); + env->SetObjectArrayElement(keys, i, jniKey.jniValue()); + + ByteArray jniData(env, (const jbyte *) service->mTextEntries[i].mData, service->mTextEntries[i].mDataSize); + env->SetObjectArrayElement(datas, i, jniData.jniValue()); + } + + jobjectArray subTypes = env->NewObjectArray(service->mSubTypeSize, stringClass, nullptr); + for (size_t i = 0; i < service->mSubTypeSize; i++) + { + UtfString jniSubType(env, service->mSubTypes[i]); + env->SetObjectArrayElement(subTypes, i, jniSubType.jniValue()); + } + + env->CallVoidMethod(sResolverObject, sPublishMethod, jniName.jniValue(), jniHostName.jniValue(), jniServiceType.jniValue(), + service->mPort, keys, datas, subTypes); + + if (env->ExceptionCheck()) + { + ChipLogError(Discovery, "Java exception in ChipDnssdPublishService"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return CHIP_JNI_ERROR_EXCEPTION_THROWN; + } + + return CHIP_NO_ERROR; } CHIP_ERROR ChipDnssdFinalizeServiceUpdate() { - return CHIP_ERROR_NOT_IMPLEMENTED; + return CHIP_NO_ERROR; } CHIP_ERROR ChipDnssdBrowse(const char * type, DnssdServiceProtocol protocol, Inet::IPAddressType addressType, @@ -120,12 +181,27 @@ void InitializeWithObjects(jobject resolverObject, jobject mdnsCallbackObject) sResolveMethod = env->GetMethodID(resolverClass, "resolve", "(Ljava/lang/String;Ljava/lang/String;JJLchip/platform/ChipMdnsCallback;)V"); - if (sResolveMethod == nullptr) { ChipLogError(Discovery, "Failed to access Resolver 'resolve' method"); env->ExceptionClear(); } + + sPublishMethod = + env->GetMethodID(resolverClass, "publish", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I[Ljava/lang/String;[[B[Ljava/lang/String;)V"); + if (sPublishMethod == nullptr) + { + ChipLogError(Discovery, "Failed to access Resolver 'publish' method"); + env->ExceptionClear(); + } + + sRemoveServicesMethod = env->GetMethodID(resolverClass, "removeServices", "()V"); + if (sRemoveServicesMethod == nullptr) + { + ChipLogError(Discovery, "Failed to access Resolver 'removeServices' method"); + env->ExceptionClear(); + } } void HandleResolve(jstring instanceName, jstring serviceType, jstring address, jint port, jlong callbackHandle, jlong contextHandle) diff --git a/src/platform/android/java/chip/platform/NsdManagerServiceResolver.java b/src/platform/android/java/chip/platform/NsdManagerServiceResolver.java index 76adab3cb3915b..b08686580fac02 100644 --- a/src/platform/android/java/chip/platform/NsdManagerServiceResolver.java +++ b/src/platform/android/java/chip/platform/NsdManagerServiceResolver.java @@ -25,6 +25,8 @@ import android.os.Handler; import android.os.Looper; import android.util.Log; +import java.util.ArrayList; +import java.util.List; public class NsdManagerServiceResolver implements ServiceResolver { private static final String TAG = NsdManagerServiceResolver.class.getSimpleName(); @@ -32,6 +34,7 @@ public class NsdManagerServiceResolver implements ServiceResolver { private final NsdManager nsdManager; private MulticastLock multicastLock; private Handler mainThreadHandler; + private List registrationListeners = new ArrayList<>(); public NsdManagerServiceResolver(Context context) { this.nsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE); @@ -112,4 +115,57 @@ public void onServiceResolved(NsdServiceInfo serviceInfo) { }); mainThreadHandler.postDelayed(timeoutRunnable, RESOLVE_SERVICE_TIMEOUT); } + + @Override + public void publish( + String serviceName, + String hostName, + String type, + int port, + String[] textEntriesKeys, + byte[][] textEntriesDatas, + String[] subTypes) { + NsdServiceInfo serviceInfo = new NsdServiceInfo(); + serviceInfo.setServiceName(serviceName); + serviceInfo.setServiceType(type); + serviceInfo.setPort(port); + Log.i(TAG, "publish serviceName=" + serviceName + " type=" + type + " port=" + port); + + NsdManager.RegistrationListener registrationListener = + new NsdManager.RegistrationListener() { + @Override + public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { + Log.w( + TAG, + "service " + serviceInfo.getServiceName() + " onRegistrationFailed:" + errorCode); + } + + @Override + public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { + Log.w( + TAG, + "service " + serviceInfo.getServiceName() + " onUnregistrationFailed:" + errorCode); + } + + @Override + public void onServiceRegistered(NsdServiceInfo serviceInfo) { + Log.i(TAG, "service " + serviceInfo.getServiceName() + " onServiceRegistered:"); + } + + @Override + public void onServiceUnregistered(NsdServiceInfo serviceInfo) { + Log.i(TAG, "service " + serviceInfo.getServiceName() + " onServiceRegistered:"); + } + }; + registrationListeners.add(registrationListener); + + nsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener); + } + + @Override + public void removeServices() { + for (NsdManager.RegistrationListener l : registrationListeners) { + nsdManager.unregisterService(l); + } + } } diff --git a/src/platform/android/java/chip/platform/ServiceResolver.java b/src/platform/android/java/chip/platform/ServiceResolver.java index e9cf638b005929..f8a50c6e37f0ec 100644 --- a/src/platform/android/java/chip/platform/ServiceResolver.java +++ b/src/platform/android/java/chip/platform/ServiceResolver.java @@ -30,4 +30,22 @@ void resolve( long callbackHandle, long contextHandle, ChipMdnsCallback chipMdnsCallback); + + /** + * Publishes a service via DNS-SD. + * + *

Calling the function again with the same service name, type, protocol, interface and port + * but different text will update the text published. + */ + void publish( + String serviceName, + String hostName, + String type, + int port, + String[] textEntriesKeys, + byte[][] textEntriesDatas, + String[] subTypes); + + /** Removes or marks all services being advertised for removal. */ + void removeServices(); }