Skip to content

Commit

Permalink
[DO NOT REVIEW][epskc] demo version impl for epskc
Browse files Browse the repository at this point in the history
  • Loading branch information
wgtdkp committed Aug 11, 2024
1 parent 4b80986 commit 59fcab9
Show file tree
Hide file tree
Showing 35 changed files with 1,437 additions and 730 deletions.
2 changes: 1 addition & 1 deletion android/build-commissioner-libs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ cmake -GNinja \
-DBUILD_SHARED_LIBS=OFF \
-DCMAKE_CXX_STANDARD=11 \
-DCMAKE_CXX_STANDARD_REQUIRED=ON \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_BUILD_TYPE=Debug \
-DOT_COMM_ANDROID=ON \
-DOT_COMM_JAVA_BINDING=ON \
-DOT_COMM_APP=OFF \
Expand Down
6 changes: 5 additions & 1 deletion android/openthread_commissioner/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,12 @@ dependencies {

implementation fileTree(dir: "libs", include: ["*.jar"])

// Fix Duplicate class
implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))

implementation 'com.google.guava:guava:31.1-jre'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.activity:activity:1.9.1'
implementation "androidx.concurrent:concurrent-futures:1.1.0"
implementation 'androidx.constraintlayout:constraintlayout:2.0.2'
implementation 'androidx.navigation:navigation-fragment:2.3.0'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package io.openthread.commissioner.app;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.ArrayMap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import androidx.annotation.Nullable;
import io.openthread.commissioner.app.BorderAgentDiscoverer.BorderAgentListener;
import java.net.Inet6Address;
import java.util.Map;
import java.util.Vector;

public class BorderAgentAdapter extends BaseAdapter implements BorderAgentListener {

private final Vector<BorderAgentInfo> borderAgentServices = new Vector<>();
private final Map<String, BorderAgentInfo> epskcServices = new ArrayMap<>();

private final LayoutInflater inflater;

BorderAgentAdapter(Context context) {
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

public void addBorderAgent(BorderAgentInfo serviceInfo) {
if (serviceInfo.isEpskcService) {
epskcServices.put(serviceInfo.instanceName, serviceInfo);
notifyDataSetChanged();
return;
}

boolean hasExistingBorderRouter = false;
for (int i = 0; i < borderAgentServices.size(); i++) {
if (borderAgentServices.get(i).instanceName.equals(serviceInfo.instanceName)) {
borderAgentServices.set(i, serviceInfo);
hasExistingBorderRouter = true;
}
}

if (!hasExistingBorderRouter) {
borderAgentServices.add(serviceInfo);
}

notifyDataSetChanged();
}

public void removeBorderAgent(boolean isEpskcService, String instanceName) {
if (isEpskcService) {
epskcServices.remove(instanceName);
} else {
borderAgentServices.removeIf(serviceInfo -> serviceInfo.instanceName.equals(instanceName));
}
notifyDataSetChanged();
}

public void clear() {
borderAgentServices.clear();
epskcServices.clear();
notifyDataSetChanged();
}

@Override
public int getCount() {
return borderAgentServices.size();
}

@Override
public Object getItem(int position) {
return borderAgentServices.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup container) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.border_agent_list_item, container, false);
}

BorderAgentInfo borderAgentInfo = borderAgentServices.get(position);

TextView instanceNameText = convertView.findViewById(R.id.border_agent_instance_name);
instanceNameText.setText(borderAgentInfo.instanceName);

TextView vendorNameText = convertView.findViewById(R.id.border_agent_vendor_name);
vendorNameText.setText(borderAgentInfo.vendorName);

TextView modelNameText = convertView.findViewById(R.id.border_agent_model_name);
modelNameText.setText(borderAgentInfo.modelName);

TextView adminModeText = convertView.findViewById(R.id.border_agent_admin_mode);
adminModeText.setText(
"In Administration Mode: " + (inAdministrationMode(borderAgentInfo) ? "YES" : "NO"));

TextView borderAgentIpAddrText = convertView.findViewById(R.id.border_agent_ip_addr);
int port =
inAdministrationMode(borderAgentInfo)
? getEpskcService(borderAgentInfo).port
: borderAgentInfo.port;
String socketAddress;
if (borderAgentInfo.host instanceof Inet6Address) {
socketAddress = "[" + borderAgentInfo.host.getHostAddress() + "]:" + port;
} else {
socketAddress = borderAgentInfo.host.getHostAddress() + ":" + port;
}
borderAgentIpAddrText.setText(socketAddress);
return convertView;
}

private boolean inAdministrationMode(BorderAgentInfo borderAgentInfo) {
return epskcServices.containsKey(borderAgentInfo.instanceName);
}

@Override
public void onBorderAgentFound(BorderAgentInfo borderAgentInfo) {
new Handler(Looper.getMainLooper()).post(() -> addBorderAgent(borderAgentInfo));
}

@Override
public void onBorderAgentLost(boolean isEpskcService, String instanceName) {
new Handler(Looper.getMainLooper()).post(() -> removeBorderAgent(isEpskcService, instanceName));
}

/**
* Returns the _meshcop-e._udp service which is associated with the given _meshcop._udp service,
* or {@code null} if such service doesn't exist.
*/
@Nullable
private BorderAgentInfo getEpskcService(BorderAgentInfo meshcopService) {
return epskcServices.get(meshcopService.instanceName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,21 @@
import java.util.concurrent.atomic.AtomicBoolean;

public class BorderAgentDiscoverer implements NsdManager.DiscoveryListener {

private static final String TAG = BorderAgentDiscoverer.class.getSimpleName();

private static final String SERVICE_TYPE = "_meshcop._udp";
public static final String MESHCOP_SERVICE_TYPE = "_meshcop._udp";
public static final String MESHCOP_E_SERVICE_TYPE = "_meshcop-e._udp";
private static final String KEY_ID = "id";
private static final String KEY_NETWORK_NAME = "nn";
private static final String KEY_EXTENDED_PAN_ID = "xp";
private static final String KEY_VENDOR_NAME = "vn";
private static final String KEY_MODEL_NAME = "mn";

private final WifiManager.MulticastLock wifiMulticastLock;
private final NsdManager nsdManager;

private WifiManager.MulticastLock wifiMulticastLock;
private NsdManager nsdManager;
private BorderAgentListener borderAgentListener;
private final String serviceType;
private final BorderAgentListener borderAgentListener;

private ExecutorService executor = Executors.newSingleThreadExecutor();
private BlockingQueue<NsdServiceInfo> unresolvedServices = new ArrayBlockingQueue<>(256);
Expand All @@ -63,19 +67,20 @@ public class BorderAgentDiscoverer implements NsdManager.DiscoveryListener {
private boolean isScanning = false;

public interface BorderAgentListener {

void onBorderAgentFound(BorderAgentInfo borderAgentInfo);

void onBorderAgentLost(byte[] id);
default void onBorderAgentLost(boolean isEpskcService, String instanceName) {}
}

@RequiresPermission(permission.INTERNET)
public BorderAgentDiscoverer(Context context, BorderAgentListener borderAgentListener) {
public BorderAgentDiscoverer(
Context context, String serviceType, BorderAgentListener borderAgentListener) {
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
wifiMulticastLock = wifi.createMulticastLock("multicastLock");

nsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);

this.serviceType = serviceType;
this.borderAgentListener = borderAgentListener;
}

Expand All @@ -91,8 +96,8 @@ public void start() {
wifiMulticastLock.acquire();

startResolver();
nsdManager.discoverServices(
BorderAgentDiscoverer.SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, this);

nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, this);
}

private void startResolver() {
Expand Down Expand Up @@ -167,7 +172,7 @@ public void stop() {

@Override
public void onDiscoveryStarted(String serviceType) {
Log.d(TAG, "start discovering Border Agent");
Log.d(TAG, "start discovering Border Agent: " + serviceType);
}

@Override
Expand All @@ -184,11 +189,9 @@ public void onServiceFound(NsdServiceInfo nsdServiceInfo) {

@Override
public void onServiceLost(NsdServiceInfo nsdServiceInfo) {
byte[] id = getBorderAgentId(nsdServiceInfo);
if (id != null) {
Log.d(TAG, "a Border Agent service is gone: " + nsdServiceInfo.getServiceName());
borderAgentListener.onBorderAgentLost(id);
}
Log.d(TAG, "a Border Agent service is gone: " + nsdServiceInfo.getServiceName());
borderAgentListener.onBorderAgentLost(
serviceType.equals(MESHCOP_E_SERVICE_TYPE), nsdServiceInfo.getServiceName());
}

@Override
Expand All @@ -204,26 +207,24 @@ public void onStopDiscoveryFailed(String serviceType, int errorCode) {
@Nullable
private BorderAgentInfo getBorderAgentInfo(NsdServiceInfo serviceInfo) {
Map<String, byte[]> attrs = serviceInfo.getAttributes();
byte[] id = getBorderAgentId(serviceInfo);

if (!attrs.containsKey(KEY_NETWORK_NAME) || !attrs.containsKey(KEY_EXTENDED_PAN_ID)) {
return null;
}

return new BorderAgentInfo(
id,
new String(attrs.get(KEY_NETWORK_NAME)),
attrs.get(KEY_EXTENDED_PAN_ID),
serviceType.equals(MESHCOP_E_SERVICE_TYPE),
serviceInfo.getServiceName(),
serviceInfo.getHost(),
serviceInfo.getPort());
serviceInfo.getPort(),
attrs.get(KEY_ID),
getStringAttribute(attrs, KEY_NETWORK_NAME),
attrs.get(KEY_EXTENDED_PAN_ID),
getStringAttribute(attrs, KEY_VENDOR_NAME),
getStringAttribute(attrs, KEY_MODEL_NAME));
}

@Nullable
private byte[] getBorderAgentId(NsdServiceInfo serviceInfo) {
Map<String, byte[]> attrs = serviceInfo.getAttributes();
if (attrs.containsKey(KEY_ID)) {
return attrs.get(KEY_ID).clone();
private static String getStringAttribute(Map<String, byte[]> attributes, String key) {
byte[] value = attributes.get(key);
if (value == null) {
return null;
}
return null;
return new String(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,49 +30,65 @@

import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.common.net.InetAddresses;
import java.net.InetAddress;
import java.net.UnknownHostException;

public class BorderAgentInfo implements Parcelable {

public byte[] id;
public String networkName;
public byte[] extendedPanId;
public InetAddress host;
public int port;
public final boolean isEpskcService;
public final String instanceName;
public final InetAddress host;
public final int port;
@Nullable public final byte[] id;
@Nullable public final String networkName;
@Nullable public final byte[] extendedPanId;
@Nullable public final String vendorName;
@Nullable public final String modelName;

public BorderAgentInfo(
@NonNull byte[] id,
@NonNull String networkName,
@NonNull byte[] extendedPanId,
@NonNull InetAddress host,
@NonNull int port) {
boolean isEpskcService,
String instanceName,
InetAddress host,
int port,
@Nullable byte[] id,
@Nullable String networkName,
@Nullable byte[] extendedPanId,
@Nullable String vendorName,
@Nullable String modelName) {
this.isEpskcService = isEpskcService;
this.instanceName = instanceName;
this.host = host;
this.port = port;
this.id = id == null ? null : id.clone();
this.networkName = networkName;
this.extendedPanId = extendedPanId == null ? null : extendedPanId.clone();
this.host = host;
this.port = port;
this.vendorName = vendorName;
this.modelName = modelName;
}

protected BorderAgentInfo(Parcel in) {
isEpskcService = in.readInt() != 0;
instanceName = in.readString();
host = InetAddresses.forString(in.readString());
port = in.readInt();
id = in.createByteArray();
networkName = in.readString();
extendedPanId = in.createByteArray();
try {
host = InetAddress.getByAddress(in.createByteArray());
} catch (UnknownHostException e) {
}
port = in.readInt();
vendorName = in.readString();
modelName = in.readString();
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(isEpskcService ? 1 : 0);
dest.writeString(instanceName);
dest.writeString(host.getHostAddress());
dest.writeInt(port);
dest.writeByteArray(id);
dest.writeString(networkName);
dest.writeByteArray(extendedPanId);
dest.writeByteArray(host.getAddress());
dest.writeInt(port);
dest.writeString(vendorName);
dest.writeString(modelName);
}

@Override
Expand Down
Loading

0 comments on commit 59fcab9

Please sign in to comment.