From ae8377c93b11af87525f3dc658890b885c81c875 Mon Sep 17 00:00:00 2001 From: swan-amazon <122404367+swan-amazon@users.noreply.github.com> Date: Fri, 24 Feb 2023 07:39:10 -0800 Subject: [PATCH] Added RegulatoryConfig support to AutoCommissioner for Android (#24413) --- examples/java-matter-controller/args.gni | 1 + .../java/src/com/matter/controller/Main.java | 3 +- .../java/CHIPDeviceController-JNI.cpp | 60 +++++++++++++++++++ .../devicecontroller/ControllerParams.java | 55 +++++++++++++++++ 4 files changed, 118 insertions(+), 1 deletion(-) diff --git a/examples/java-matter-controller/args.gni b/examples/java-matter-controller/args.gni index 874fcdc22bb29c..188c73238f6a2b 100644 --- a/examples/java-matter-controller/args.gni +++ b/examples/java-matter-controller/args.gni @@ -23,3 +23,4 @@ chip_system_project_config_include = "" chip_project_config_include_dirs = [ "${chip_root}/examples/java-matter-controller/include" ] chip_project_config_include_dirs += [ "${chip_root}/config/standalone" ] +chip_stack_lock_tracking = "none" diff --git a/examples/java-matter-controller/java/src/com/matter/controller/Main.java b/examples/java-matter-controller/java/src/com/matter/controller/Main.java index c524dbd237050f..59c2e666589365 100644 --- a/examples/java-matter-controller/java/src/com/matter/controller/Main.java +++ b/examples/java-matter-controller/java/src/com/matter/controller/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Project CHIP Authors + * Copyright (c) 2022-2023 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -105,6 +105,7 @@ public static void main(String[] args) { ControllerParams.newBuilder() .setUdpListenPort(0) .setControllerVendorId(0xFFF1) + .setCountryCode("US") .build()); CredentialsIssuer credentialsIssuer = new CredentialsIssuer(); diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp index 90aaee7e34be60..7601f867dd4487 100644 --- a/src/controller/java/CHIPDeviceController-JNI.cpp +++ b/src/controller/java/CHIPDeviceController-JNI.cpp @@ -303,6 +303,16 @@ JNI_METHOD(jlong, newDeviceController)(JNIEnv * env, jobject self, jobject contr &getSkipCommissioningComplete); SuccessOrExit(err); + jmethodID getCountryCode; + err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getCountryCode", "()Ljava/util/Optional;", + &getCountryCode); + SuccessOrExit(err); + + jmethodID getRegulatoryLocation; + err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getRegulatoryLocation", "()Ljava/util/Optional;", + &getRegulatoryLocation); + SuccessOrExit(err); + jmethodID getKeypairDelegate; err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getKeypairDelegate", "()Lchip/devicecontroller/KeypairDelegate;", &getKeypairDelegate); @@ -345,6 +355,8 @@ JNI_METHOD(jlong, newDeviceController)(JNIEnv * env, jobject self, jobject contr bool attemptNetworkScanThread = env->CallBooleanMethod(controllerParams, getAttemptNetworkScanThread); bool skipCommissioningComplete = env->CallBooleanMethod(controllerParams, getSkipCommissioningComplete); uint64_t adminSubject = env->CallLongMethod(controllerParams, getAdminSubject); + jobject countryCodeOptional = env->CallObjectMethod(controllerParams, getCountryCode); + jobject regulatoryLocationOptional = env->CallObjectMethod(controllerParams, getRegulatoryLocation); #ifdef JAVA_MATTER_CONTROLLER_TEST std::unique_ptr opCredsIssuer( @@ -384,6 +396,54 @@ JNI_METHOD(jlong, newDeviceController)(JNIEnv * env, jobject self, jobject contr SuccessOrExit(err); } } + + jobject countryCode; + err = chip::JniReferences::GetInstance().GetOptionalValue(countryCodeOptional, countryCode); + SuccessOrExit(err); + + if (countryCode != nullptr) + { + jstring countryCodeStr = static_cast(countryCode); + JniUtfString countryCodeJniString(env, countryCodeStr); + + VerifyOrExit(countryCodeJniString.size() == 2, err = CHIP_ERROR_INVALID_ARGUMENT); + + chip::Controller::CommissioningParameters commissioningParams = wrapper->GetCommissioningParameters(); + commissioningParams.SetCountryCode(countryCodeJniString.charSpan()); + + // The wrapper internally has reserved storage for the country code and will copy the value. + err = wrapper->UpdateCommissioningParameters(commissioningParams); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "UpdateCommissioningParameters failed. Err = %" CHIP_ERROR_FORMAT, err.Format()); + SuccessOrExit(err); + } + } + + jobject regulatoryLocation; + err = chip::JniReferences::GetInstance().GetOptionalValue(regulatoryLocationOptional, regulatoryLocation); + SuccessOrExit(err); + + if (regulatoryLocation != nullptr) + { + using namespace app::Clusters::GeneralCommissioning; + + jint regulatoryLocationJint = chip::JniReferences::GetInstance().IntegerToPrimitive(regulatoryLocation); + VerifyOrExit(chip::CanCastTo(regulatoryLocationJint), err = CHIP_ERROR_INVALID_ARGUMENT); + + RegulatoryLocationType regulatoryLocationType = static_cast(regulatoryLocationJint); + VerifyOrExit(regulatoryLocationType >= RegulatoryLocationType::kIndoor, err = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(regulatoryLocationType <= RegulatoryLocationType::kIndoorOutdoor, err = CHIP_ERROR_INVALID_ARGUMENT); + + chip::Controller::CommissioningParameters commissioningParams = wrapper->GetCommissioningParameters(); + commissioningParams.SetDeviceRegulatoryLocation(regulatoryLocationType); + err = wrapper->UpdateCommissioningParameters(commissioningParams); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "UpdateCommissioningParameters failed. Err = %" CHIP_ERROR_FORMAT, err.Format()); + SuccessOrExit(err); + } + } } // Create and start the IO thread. Must be called after Controller()->Init diff --git a/src/controller/java/src/chip/devicecontroller/ControllerParams.java b/src/controller/java/src/chip/devicecontroller/ControllerParams.java index 5c13d853f84c59..a746dd43ad6e17 100644 --- a/src/controller/java/src/chip/devicecontroller/ControllerParams.java +++ b/src/controller/java/src/chip/devicecontroller/ControllerParams.java @@ -1,5 +1,6 @@ package chip.devicecontroller; +import java.util.Optional; import javax.annotation.Nullable; /** Parameters representing initialization arguments for {@link ChipDeviceController}. */ @@ -13,6 +14,8 @@ public final class ControllerParams { private final boolean attemptNetworkScanWiFi; private final boolean attemptNetworkScanThread; private final boolean skipCommissioningComplete; + private final Optional countryCode; + private final Optional regulatoryLocationType; @Nullable private final KeypairDelegate keypairDelegate; @Nullable private final byte[] rootCertificate; @Nullable private final byte[] intermediateCertificate; @@ -32,6 +35,8 @@ private ControllerParams(Builder builder) { this.attemptNetworkScanWiFi = builder.attemptNetworkScanWiFi; this.attemptNetworkScanThread = builder.attemptNetworkScanThread; this.skipCommissioningComplete = builder.skipCommissioningComplete; + this.countryCode = builder.countryCode; + this.regulatoryLocationType = builder.regulatoryLocationType; this.keypairDelegate = builder.keypairDelegate; this.rootCertificate = builder.rootCertificate; this.intermediateCertificate = builder.intermediateCertificate; @@ -73,6 +78,14 @@ public boolean getSkipCommissioningComplete() { return skipCommissioningComplete; } + public Optional getCountryCode() { + return countryCode; + } + + public Optional getRegulatoryLocation() { + return regulatoryLocationType; + } + public KeypairDelegate getKeypairDelegate() { return keypairDelegate; } @@ -126,6 +139,8 @@ public static class Builder { private boolean attemptNetworkScanWiFi = false; private boolean attemptNetworkScanThread = false; private boolean skipCommissioningComplete = false; + private Optional countryCode = Optional.empty(); + private Optional regulatoryLocationType = Optional.empty(); @Nullable private KeypairDelegate keypairDelegate = null; @Nullable private byte[] rootCertificate = null; @Nullable private byte[] intermediateCertificate = null; @@ -247,6 +262,46 @@ public Builder setSkipCommissioningComplete(boolean skipCommissioningComplete) { return this; } + /** + * Sets the Regulatory Location country code passed to ChipDeviceCommissioner's + * CommissioningParameters. + * + *

Setting the country code will set the CountryCode when the SetRegulatoryConfig command is + * sent by this ChipDeviceCommissioner. + * + * @param countryCode an ISO 3166-1 alpha-2 code to represent the country, dependent territory, + * or special area of geographic interest + * @return + */ + public Builder setCountryCode(final String countryCode) { + if (countryCode == null || countryCode.length() != 2) { + throw new IllegalArgumentException("countryCode must be 2 characters"); + } + this.countryCode = Optional.of(countryCode); + return this; + } + + /** + * Sets the Regulatory Location capability passed to ChipDeviceCommissioner's + * CommissioningParameters. + * + *

Setting the regulatory location type will set the NewRegulatoryConfig when the + * SetRegulatoryConfig command is sent by this ChipDeviceCommissioner. + * + * @param regulatoryLocation an app::Clusters::GeneralCommissioning::RegulatoryLocationType enum + * value + * @return + */ + public Builder setRegulatoryLocation(int regulatoryLocation) { + if ((regulatoryLocation < 0) || (regulatoryLocation > 2)) { + throw new IllegalArgumentException( + "regulatoryLocation value must be between RegulatoryLocationType::kIndoor and " + + "RegulatoryLocationType::kIndoorOutdoor"); + } + this.regulatoryLocationType = Optional.of(regulatoryLocation); + return this; + } + public Builder setKeypairDelegate(KeypairDelegate keypairDelegate) { this.keypairDelegate = keypairDelegate; return this;