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 Apr 14, 2024
1 parent 0d6cfcc commit af82706
Show file tree
Hide file tree
Showing 20 changed files with 1,100 additions and 54 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
2 changes: 1 addition & 1 deletion android/openthread_commissioner/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ android {

defaultConfig {
applicationId "io.openthread.commissioner.app"
minSdkVersion 24
minSdkVersion 26
targetSdkVersion 34
versionCode 1
versionName "0.0.1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,29 @@
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import io.openthread.commissioner.service.BorderAgentInfo;
import io.openthread.commissioner.service.FragmentCallback;
import io.openthread.commissioner.service.GetAdminPasscodeFragment;
import io.openthread.commissioner.service.JoinerDeviceInfo;
import io.openthread.commissioner.service.MeshcopFragment;
import io.openthread.commissioner.service.RetrieveDatasetFragment;
import io.openthread.commissioner.service.ScanQrCodeFragment;
import io.openthread.commissioner.service.SelectBorderRouterFragment;
import io.openthread.commissioner.service.SelectNetworkFragment;
import io.openthread.commissioner.service.ThreadNetworkInfoHolder;

public class MainActivity extends AppCompatActivity implements FragmentCallback {

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

@Nullable private ThreadNetworkInfoHolder selectedNetwork;
@Nullable
private ThreadNetworkInfoHolder selectedNetwork;

@Nullable private byte[] pskc;
@Nullable
private byte[] pskc;

@Nullable private JoinerDeviceInfo joinerDeviceInfo;
@Nullable
private JoinerDeviceInfo joinerDeviceInfo;

@Override
protected void onCreate(Bundle savedInstanceState) {
Expand All @@ -69,7 +76,7 @@ protected void onCreate(Bundle savedInstanceState) {
gitHash.setText(BuildConfig.GIT_HASH);

if (savedInstanceState == null) {
showFragment(new SelectNetworkFragment(this, null), false);
showFragment(new SelectBorderRouterFragment(this), false);
}
}

Expand Down Expand Up @@ -154,4 +161,24 @@ public void onJoinerInfoReceived(@Nullable JoinerDeviceInfo joinerDeviceInfo) {
public void onMeshcopResult(int result) {
finishCommissioning(result);
}

@Override
public void onGetAdminPasscodeStarted(BorderAgentInfo borderAgentInfo) {
showFragment(new GetAdminPasscodeFragment(this, borderAgentInfo), /* addToBackStack= */ true);
}

@Override
public void onAdminPasscodeReceived(BorderAgentInfo borderAgentInfo, String passcode,
int epskcPort) {
showFragment(new RetrieveDatasetFragment(this, borderAgentInfo, passcode,
epskcPort), /* addToBackStack= */ true);
}

@Override
public void onCredentialsRetrieved() {
selectedNetwork = null;
pskc = null;
joinerDeviceInfo = null;
clearFragmentsInBackStack();
}
}
4 changes: 3 additions & 1 deletion android/openthread_commissioner/service/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ android {
compileSdkVersion 34

defaultConfig {
minSdkVersion 24
minSdkVersion 26
targetSdkVersion 34

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
Expand Down Expand Up @@ -73,10 +73,12 @@ dependencies {

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

implementation 'com.google.guava:guava:31.1-jre'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.2'
implementation 'androidx.navigation:navigation-fragment:2.3.0'
implementation 'com.google.android.gms:play-services-vision:20.1.3+'
implementation 'com.google.android.gms:play-services-threadnetwork:16.0.0'
implementation 'com.google.android.material:material:1.2.1'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package io.openthread.commissioner.service;

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.service.BorderAgentDiscoverer.BorderAgentListener;
import java.net.Inet6Address;
import java.net.SocketAddress;
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 @@ -34,6 +34,7 @@
import android.net.nsd.NsdServiceInfo;
import android.net.wifi.WifiManager;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresPermission;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
Expand All @@ -46,14 +47,20 @@ 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_DISCRIMINATOR = "discriminator";
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 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 @@ -64,16 +71,19 @@ public class BorderAgentDiscoverer implements NsdManager.DiscoveryListener {
public interface BorderAgentListener {
void onBorderAgentFound(BorderAgentInfo borderAgentInfo);

void onBorderAgentLost(String discriminator);
default void onBorderAgentLost(String discriminator) {}

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 @@ -89,8 +99,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 @@ -165,7 +175,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 @@ -187,6 +197,8 @@ public void onServiceLost(NsdServiceInfo nsdServiceInfo) {
Log.d(TAG, "a Border Agent service is gone");
borderAgentListener.onBorderAgentLost(discriminator);
}

borderAgentListener.onBorderAgentLost(serviceType.equals(MESHCOP_E_SERVICE_TYPE), nsdServiceInfo.getServiceName());
}

@Override
Expand All @@ -209,16 +221,26 @@ private BorderAgentInfo getBorderAgentInfo(NsdServiceInfo serviceInfo) {
discriminator = new String(attrs.get(KEY_DISCRIMINATOR));
}

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

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

@Nullable
private static String getStringAttribute(Map<String, byte[]> attributes, String key) {
byte[] value = attributes.get(key);
if (value == null) {
return null;
}
return new String(value);
}

private String getBorderAgentDiscriminator(NsdServiceInfo serviceInfo) {
Expand Down
Loading

0 comments on commit af82706

Please sign in to comment.