From 1314929e9af2e0209407f665053026d89ab2445e Mon Sep 17 00:00:00 2001 From: Austin Hsieh Date: Wed, 7 Jul 2021 14:52:31 -0700 Subject: [PATCH] Support discovery capabilities in setup payload --- .../google/chip/chiptool/CHIPToolActivity.kt | 10 +-- .../setuppayloadscanner/BarcodeFragment.kt | 12 +-- .../CHIPDeviceDetailsFragment.kt | 73 ++++++++++--------- .../setuppayloadscanner/CHIPDeviceInfo.kt | 42 +++++++++-- .../res/layout/chip_device_info_fragment.xml | 22 +++--- .../app/src/main/res/values/strings.xml | 2 +- src/setup_payload/java/BUILD.gn | 1 + .../java/SetupPayloadParser-JNI.cpp | 47 ++++++++++-- .../setuppayload/DiscoveryCapability.java | 8 ++ .../src/chip/setuppayload/SetupPayload.java | 7 +- 10 files changed, 141 insertions(+), 83 deletions(-) create mode 100644 src/setup_payload/java/src/chip/setuppayload/DiscoveryCapability.java diff --git a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/CHIPToolActivity.kt b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/CHIPToolActivity.kt index fb2f166f49a7f8..c50f8e523ea12f 100644 --- a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/CHIPToolActivity.kt +++ b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/CHIPToolActivity.kt @@ -36,7 +36,6 @@ import com.google.chip.chiptool.provisioning.ProvisionNetworkType import com.google.chip.chiptool.setuppayloadscanner.BarcodeFragment import com.google.chip.chiptool.setuppayloadscanner.CHIPDeviceDetailsFragment import com.google.chip.chiptool.setuppayloadscanner.CHIPDeviceInfo -import com.google.chip.chiptool.setuppayloadscanner.QrCodeInfo import chip.devicecontroller.PreferencesKeyValueStoreManager import chip.setuppayload.SetupPayload import chip.setuppayload.SetupPayloadParser @@ -160,14 +159,7 @@ class CHIPToolActivity : return } - val deviceInfo = CHIPDeviceInfo( - setupPayload.version, - setupPayload.vendorId, - setupPayload.productId, - setupPayload.discriminator, - setupPayload.setupPinCode, - setupPayload.optionalQRCodeInfo.mapValues { (_, info) -> QrCodeInfo(info.tag, info.type, info.data, info.int32) } - ) + val deviceInfo = CHIPDeviceInfo.fromSetupPayload(setupPayload) val buttons = arrayOf( getString(R.string.nfc_tag_action_show), diff --git a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/BarcodeFragment.kt b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/BarcodeFragment.kt index 220d0b89aac6c1..40c5f250f0252d 100644 --- a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/BarcodeFragment.kt +++ b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/BarcodeFragment.kt @@ -133,18 +133,8 @@ class BarcodeFragment : Fragment(), CHIPBarcodeProcessor.BarcodeDetectionListene } return@post } - val deviceInfo = CHIPDeviceInfo( - payload.version, - payload.vendorId, - payload.productId, - payload.discriminator, - payload.setupPinCode, - payload.optionalQRCodeInfo.mapValues { (_, info) -> - QrCodeInfo(info.tag, info.type, info.data, info.int32) - } - ) FragmentUtil.getHost(this, Callback::class.java) - ?.onCHIPDeviceInfoReceived(deviceInfo) + ?.onCHIPDeviceInfoReceived(CHIPDeviceInfo.fromSetupPayload(payload)) } } diff --git a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/CHIPDeviceDetailsFragment.kt b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/CHIPDeviceDetailsFragment.kt index cdcd5524f916ce..afcfb015d69f79 100644 --- a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/CHIPDeviceDetailsFragment.kt +++ b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/CHIPDeviceDetailsFragment.kt @@ -25,6 +25,7 @@ import android.view.ViewGroup import android.widget.TextView import androidx.fragment.app.Fragment import com.google.chip.chiptool.R +import kotlinx.android.synthetic.main.chip_device_info_fragment.view.discoveryCapabilitiesTv import kotlinx.android.synthetic.main.chip_device_info_fragment.view.discriminatorTv import kotlinx.android.synthetic.main.chip_device_info_fragment.view.productIdTv import kotlinx.android.synthetic.main.chip_device_info_fragment.view.setupCodeTv @@ -36,48 +37,52 @@ import kotlinx.android.synthetic.main.chip_device_info_fragment.view.versionTv /** Show the [CHIPDeviceInfo]. */ class CHIPDeviceDetailsFragment : Fragment() { - private lateinit var deviceInfo: CHIPDeviceInfo + private lateinit var deviceInfo: CHIPDeviceInfo - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - deviceInfo = checkNotNull(requireArguments().getParcelable(ARG_DEVICE_INFO)) + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + deviceInfo = checkNotNull(requireArguments().getParcelable(ARG_DEVICE_INFO)) - return inflater.inflate(R.layout.chip_device_info_fragment, container, false).apply { + return inflater.inflate(R.layout.chip_device_info_fragment, container, false).apply { - // Display CHIP setup code info to user for manual connect to soft AP - versionTv.text = "${deviceInfo.version}" - vendorIdTv.text = "${deviceInfo.vendorId}" - productIdTv.text = "${deviceInfo.productId}" - setupCodeTv.text = "${deviceInfo.setupPinCode}" - discriminatorTv.text = "${deviceInfo.discriminator}" + versionTv.text = "${deviceInfo.version}" + vendorIdTv.text = "${deviceInfo.vendorId}" + productIdTv.text = "${deviceInfo.productId}" + setupCodeTv.text = "${deviceInfo.setupPinCode}" + discriminatorTv.text = "${deviceInfo.discriminator}" + discoveryCapabilitiesTv.text = requireContext().getString( + R.string.chip_device_info_discovery_capabilities_text, + deviceInfo.discoveryCapabilities + ) - if (deviceInfo.optionalQrCodeInfoMap.isEmpty()) { - vendorTagsLabelTv.visibility = View.GONE - vendorTagsContainer.visibility = View.GONE - } else { - vendorTagsLabelTv.visibility = View.VISIBLE - vendorTagsContainer.visibility = View.VISIBLE + if (deviceInfo.optionalQrCodeInfoMap.isEmpty()) { + vendorTagsLabelTv.visibility = View.GONE + vendorTagsContainer.visibility = View.GONE + } else { + vendorTagsLabelTv.visibility = View.VISIBLE + vendorTagsContainer.visibility = View.VISIBLE - deviceInfo.optionalQrCodeInfoMap.forEach { (_, qrCodeInfo) -> - val tv = inflater.inflate(R.layout.barcode_vendor_tag, null, false) as TextView - val info = "${qrCodeInfo.tag}. ${qrCodeInfo.data}, ${qrCodeInfo.intDataValue}" - tv.text = info - vendorTagsContainer.addView(tv) - } - } + deviceInfo.optionalQrCodeInfoMap.forEach { (_, qrCodeInfo) -> + val tv = inflater.inflate(R.layout.barcode_vendor_tag, null, false) as TextView + val info = "${qrCodeInfo.tag}. ${qrCodeInfo.data}, ${qrCodeInfo.intDataValue}" + tv.text = info + vendorTagsContainer.addView(tv) } + } } + } - companion object { - private const val ARG_DEVICE_INFO = "device_info" + companion object { + private const val ARG_DEVICE_INFO = "device_info" - @JvmStatic fun newInstance(deviceInfo: CHIPDeviceInfo): CHIPDeviceDetailsFragment { - return CHIPDeviceDetailsFragment().apply { - arguments = Bundle(1).apply { putParcelable(ARG_DEVICE_INFO, deviceInfo) } - } - } + @JvmStatic + fun newInstance(deviceInfo: CHIPDeviceInfo): CHIPDeviceDetailsFragment { + return CHIPDeviceDetailsFragment().apply { + arguments = Bundle(1).apply { putParcelable(ARG_DEVICE_INFO, deviceInfo) } + } } + } } diff --git a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/CHIPDeviceInfo.kt b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/CHIPDeviceInfo.kt index 1a3d5bdadd3c77..f63d608d31f5b5 100644 --- a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/CHIPDeviceInfo.kt +++ b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/CHIPDeviceInfo.kt @@ -19,14 +19,40 @@ package com.google.chip.chiptool.setuppayloadscanner import android.os.Parcelable +import chip.setuppayload.DiscoveryCapability +import chip.setuppayload.SetupPayload import kotlinx.android.parcel.Parcelize /** Class to hold the CHIP device information. */ -@Parcelize data class CHIPDeviceInfo( - val version: Int, - val vendorId: Int, - val productId: Int, - val discriminator: Int, - val setupPinCode: Long, - val optionalQrCodeInfoMap: Map -) : Parcelable +@Parcelize +data class CHIPDeviceInfo( + val version: Int, + val vendorId: Int, + val productId: Int, + val discriminator: Int, + val setupPinCode: Long, + val optionalQrCodeInfoMap: Map, + val discoveryCapabilities: Set +) : Parcelable { + + companion object { + fun fromSetupPayload(setupPayload: SetupPayload): CHIPDeviceInfo { + return CHIPDeviceInfo( + setupPayload.version, + setupPayload.vendorId, + setupPayload.productId, + setupPayload.discriminator, + setupPayload.setupPinCode, + setupPayload.optionalQRCodeInfo.mapValues { (_, info) -> + QrCodeInfo( + info.tag, + info.type, + info.data, + info.int32 + ) + }, + setupPayload.discoveryCapabilities + ) + } + } +} diff --git a/src/android/CHIPTool/app/src/main/res/layout/chip_device_info_fragment.xml b/src/android/CHIPTool/app/src/main/res/layout/chip_device_info_fragment.xml index 6d1686491f0db7..bbcdf5efee899b 100644 --- a/src/android/CHIPTool/app/src/main/res/layout/chip_device_info_fragment.xml +++ b/src/android/CHIPTool/app/src/main/res/layout/chip_device_info_fragment.xml @@ -17,22 +17,13 @@ android:layout_alignParentTop="true" android:textSize="20sp"/> - - @@ -142,5 +133,14 @@ android:orientation="vertical" android:layout_marginBottom="8dp" android:layout_below="@id/vendorTagsLabelTv"/> + + diff --git a/src/android/CHIPTool/app/src/main/res/values/strings.xml b/src/android/CHIPTool/app/src/main/res/values/strings.xml index 9ca6b5537936b4..cbdcd7cc49680f 100644 --- a/src/android/CHIPTool/app/src/main/res/values/strings.xml +++ b/src/android/CHIPTool/app/src/main/res/values/strings.xml @@ -5,13 +5,13 @@ Location permission required Since location permission was denied, some functions of the app may be unavailable. CHIP Device Info: - Please manually connect to this device\'s soft AP using the information below. Version: Vendor ID: Product ID: Discriminator: Setup PIN Code: Optional Vendor tags: + Discovery capabilities: %1s Camera permission missing Camera permission required to be able to scan the QR code. Try again diff --git a/src/setup_payload/java/BUILD.gn b/src/setup_payload/java/BUILD.gn index fcff906e5efe10..ae8d01118e2cc6 100644 --- a/src/setup_payload/java/BUILD.gn +++ b/src/setup_payload/java/BUILD.gn @@ -40,6 +40,7 @@ android_library("java") { ] sources = [ + "src/chip/setuppayload/DiscoveryCapability.java", "src/chip/setuppayload/OptionalQRCodeInfo.java", "src/chip/setuppayload/SetupPayload.java", "src/chip/setuppayload/SetupPayloadParser.java", diff --git a/src/setup_payload/java/SetupPayloadParser-JNI.cpp b/src/setup_payload/java/SetupPayloadParser-JNI.cpp index 0b069671dd2b4e..4de2d5cf0b75f3 100644 --- a/src/setup_payload/java/SetupPayloadParser-JNI.cpp +++ b/src/setup_payload/java/SetupPayloadParser-JNI.cpp @@ -24,6 +24,7 @@ using namespace chip; #define JNI_METHOD(RETURN, METHOD_NAME) extern "C" JNIEXPORT RETURN JNICALL Java_chip_setuppayload_SetupPayloadParser_##METHOD_NAME static jobject TransformSetupPayload(JNIEnv * env, SetupPayload & payload); +static jobject CreateCapabilitiesHashSet(JNIEnv * env, RendezvousInformationFlags flags); static CHIP_ERROR ThrowUnrecognizedQRCodeException(JNIEnv * env, jstring qrCodeObj); static CHIP_ERROR ThrowInvalidEntryCodeFormatException(JNIEnv * env, jstring entryCodeObj); @@ -88,12 +89,13 @@ jobject TransformSetupPayload(JNIEnv * env, SetupPayload & payload) jmethodID setupConstr = env->GetMethodID(setupPayloadClass, "", "()V"); jobject setupPayload = env->NewObject(setupPayloadClass, setupConstr); - jfieldID version = env->GetFieldID(setupPayloadClass, "version", "I"); - jfieldID vendorId = env->GetFieldID(setupPayloadClass, "vendorId", "I"); - jfieldID productId = env->GetFieldID(setupPayloadClass, "productId", "I"); - jfieldID commissioningFlow = env->GetFieldID(setupPayloadClass, "commissioningFlow", "I"); - jfieldID discriminator = env->GetFieldID(setupPayloadClass, "discriminator", "I"); - jfieldID setUpPinCode = env->GetFieldID(setupPayloadClass, "setupPinCode", "J"); + jfieldID version = env->GetFieldID(setupPayloadClass, "version", "I"); + jfieldID vendorId = env->GetFieldID(setupPayloadClass, "vendorId", "I"); + jfieldID productId = env->GetFieldID(setupPayloadClass, "productId", "I"); + jfieldID commissioningFlow = env->GetFieldID(setupPayloadClass, "commissioningFlow", "I"); + jfieldID discriminator = env->GetFieldID(setupPayloadClass, "discriminator", "I"); + jfieldID setUpPinCode = env->GetFieldID(setupPayloadClass, "setupPinCode", "J"); + jfieldID discoveryCapabilities = env->GetFieldID(setupPayloadClass, "discoveryCapabilities", "Ljava/util/Set;"); env->SetIntField(setupPayload, version, payload.version); env->SetIntField(setupPayload, vendorId, payload.vendorID); @@ -102,6 +104,8 @@ jobject TransformSetupPayload(JNIEnv * env, SetupPayload & payload) env->SetIntField(setupPayload, discriminator, payload.discriminator); env->SetLongField(setupPayload, setUpPinCode, payload.setUpPINCode); + env->SetObjectField(setupPayload, discoveryCapabilities, CreateCapabilitiesHashSet(env, payload.rendezvousInformation)); + jmethodID addOptionalInfoMid = env->GetMethodID(setupPayloadClass, "addOptionalQRCodeInfo", "(Lchip/setuppayload/OptionalQRCodeInfo;)V"); @@ -163,6 +167,37 @@ jobject TransformSetupPayload(JNIEnv * env, SetupPayload & payload) return setupPayload; } +jobject CreateCapabilitiesHashSet(JNIEnv * env, RendezvousInformationFlags flags) +{ + jclass hashSetClass = env->FindClass("java/util/HashSet"); + jmethodID hashSetConstructor = env->GetMethodID(hashSetClass, "", "()V"); + jobject capabilitiesHashSet = env->NewObject(hashSetClass, hashSetConstructor); + + jmethodID hashSetAddMethod = env->GetMethodID(hashSetClass, "add", "(Ljava/lang/Object;)Z"); + jclass capabilityEnum = env->FindClass("chip/setuppayload/DiscoveryCapability"); + + if (flags.Has(chip::RendezvousInformationFlag::kBLE)) + { + jfieldID bleCapability = env->GetStaticFieldID(capabilityEnum, "BLE", "Lchip/setuppayload/DiscoveryCapability;"); + jobject enumObj = env->GetStaticObjectField(capabilityEnum, bleCapability); + env->CallBooleanMethod(capabilitiesHashSet, hashSetAddMethod, enumObj); + } + if (flags.Has(chip::RendezvousInformationFlag::kSoftAP)) + { + jfieldID softApCapability = env->GetStaticFieldID(capabilityEnum, "SOFT_AP", "Lchip/setuppayload/DiscoveryCapability;"); + jobject enumObj = env->GetStaticObjectField(capabilityEnum, softApCapability); + env->CallBooleanMethod(capabilitiesHashSet, hashSetAddMethod, enumObj); + } + if (flags.Has(chip::RendezvousInformationFlag::kOnNetwork)) + { + jfieldID onNetworkCapability = + env->GetStaticFieldID(capabilityEnum, "ON_NETWORK", "Lchip/setuppayload/DiscoveryCapability;"); + jobject enumObj = env->GetStaticObjectField(capabilityEnum, onNetworkCapability); + env->CallBooleanMethod(capabilitiesHashSet, hashSetAddMethod, enumObj); + } + return capabilitiesHashSet; +} + CHIP_ERROR ThrowUnrecognizedQRCodeException(JNIEnv * env, jstring qrCodeObj) { jclass exceptionCls = nullptr; diff --git a/src/setup_payload/java/src/chip/setuppayload/DiscoveryCapability.java b/src/setup_payload/java/src/chip/setuppayload/DiscoveryCapability.java new file mode 100644 index 00000000000000..06811152172d78 --- /dev/null +++ b/src/setup_payload/java/src/chip/setuppayload/DiscoveryCapability.java @@ -0,0 +1,8 @@ +package chip.setuppayload; + +/** Enum values for possible bits in the onboarding paylod's discovery capabilities bitmask. */ +public enum DiscoveryCapability { + SOFT_AP, + BLE, + ON_NETWORK +} diff --git a/src/setup_payload/java/src/chip/setuppayload/SetupPayload.java b/src/setup_payload/java/src/chip/setuppayload/SetupPayload.java index 2cd33ffc377462..5d702ad8da4297 100644 --- a/src/setup_payload/java/src/chip/setuppayload/SetupPayload.java +++ b/src/setup_payload/java/src/chip/setuppayload/SetupPayload.java @@ -2,6 +2,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Set; /** Class to hold the data from the scanned QR code or manual entry code. */ public class SetupPayload { @@ -14,7 +15,7 @@ public class SetupPayload { /** Commissioning flow: 0 = standard, 1 = requires user action, 2 = custom */ public int commissioningFlow; /** The CHIP device supported rendezvous flags */ - public int rendezvousInformation; + public Set discoveryCapabilities; /** The CHIP device discriminator */ public int discriminator; /** The CHIP device manual setup code */ @@ -31,14 +32,14 @@ public SetupPayload( int vendorId, int productId, int commissioningFlow, - int rendezvousInfo, + Set discoveryCapabilities, int discriminator, long setupPinCode) { this.version = version; this.vendorId = vendorId; this.productId = productId; this.commissioningFlow = commissioningFlow; - this.rendezvousInformation = rendezvousInfo; + this.discoveryCapabilities = discoveryCapabilities; this.discriminator = discriminator; this.setupPinCode = setupPinCode; this.optionalQRCodeInfo = new HashMap();