Skip to content

Commit

Permalink
Support discovery capabilities in setup payload (project-chip#8178)
Browse files Browse the repository at this point in the history
  • Loading branch information
austinh0 authored and Nikita committed Sep 23, 2021
1 parent 00e046b commit 554b1a8
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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) }
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<Int, QrCodeInfo>
) : Parcelable
@Parcelize
data class CHIPDeviceInfo(
val version: Int,
val vendorId: Int,
val productId: Int,
val discriminator: Int,
val setupPinCode: Long,
val optionalQrCodeInfoMap: Map<Int, QrCodeInfo>,
val discoveryCapabilities: Set<DiscoveryCapability>
) : 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
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,13 @@
android:layout_alignParentTop="true"
android:textSize="20sp"/>

<TextView
android:id="@+id/subtitleTv"
android:text="@string/chip_device_info_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_below="@id/titleTv"
android:textSize="20sp"/>

<TextView
android:id="@+id/versionLabelTv"
android:text="@string/chip_device_info_version_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_below="@id/subtitleTv"
android:layout_below="@id/titleTv"
android:layout_alignParentStart="true"
android:textSize="20sp"/>
<TextView
Expand All @@ -41,7 +32,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginBottom="8dp"
android:layout_below="@id/subtitleTv"
android:layout_below="@id/titleTv"
android:layout_toEndOf="@id/versionLabelTv"
android:layout_alignParentEnd="true"
android:textSize="20sp"/>
Expand Down Expand Up @@ -142,5 +133,14 @@
android:orientation="vertical"
android:layout_marginBottom="8dp"
android:layout_below="@id/vendorTagsLabelTv"/>

<TextView
android:id="@+id/discoveryCapabilitiesTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_below="@id/vendorTagsContainer"
android:layout_alignParentStart="true"
android:textSize="20sp"/>
</RelativeLayout>
</ScrollView>
2 changes: 1 addition & 1 deletion src/android/CHIPTool/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
<string name="location_permission_denied_title">Location permission required</string>
<string name="location_permission_denied_message">Since location permission was denied, some functions of the app may be unavailable. </string>
<string name="chip_device_info_title">CHIP Device Info:</string>
<string name="chip_device_info_subtitle">Please manually connect to this device\'s soft AP using the information below.</string>
<string name="chip_device_info_version_label">Version:</string>
<string name="chip_device_info_vendor_id_label">Vendor ID:</string>
<string name="chip_device_info_product_id_label">Product ID:</string>
<string name="chip_device_info_discriminator_label">Discriminator:</string>
<string name="chip_device_info_setup_code_label">Setup PIN Code:</string>
<string name="chip_device_info_optional_vendor_tags_label">Optional Vendor tags:</string>
<string name="chip_device_info_discovery_capabilities_text">Discovery capabilities: %1s</string>
<string name="camera_permission_missing_alert_title">Camera permission missing</string>
<string name="camera_permission_missing_alert_subtitle">Camera permission required to be able to scan the QR code.</string>
<string name="camera_permission_missing_alert_try_again">Try again</string>
Expand Down
1 change: 1 addition & 0 deletions src/setup_payload/java/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
47 changes: 41 additions & 6 deletions src/setup_payload/java/SetupPayloadParser-JNI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -88,12 +89,13 @@ jobject TransformSetupPayload(JNIEnv * env, SetupPayload & payload)
jmethodID setupConstr = env->GetMethodID(setupPayloadClass, "<init>", "()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);
Expand All @@ -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");

Expand Down Expand Up @@ -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, "<init>", "()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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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<DiscoveryCapability> discoveryCapabilities;
/** The CHIP device discriminator */
public int discriminator;
/** The CHIP device manual setup code */
Expand All @@ -31,14 +32,14 @@ public SetupPayload(
int vendorId,
int productId,
int commissioningFlow,
int rendezvousInfo,
Set<DiscoveryCapability> 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<Integer, OptionalQRCodeInfo>();
Expand Down

0 comments on commit 554b1a8

Please sign in to comment.