Skip to content

Commit

Permalink
First attempt at Network State Change listening
Browse files Browse the repository at this point in the history
- Revised some of the data used for ListenIfAdapter;
- NetworkInterfaceTester is a class that report change on network state, it's still a WIP, it is now used to update the Spinner in relation to the available network interfaces;
  • Loading branch information
elluisian committed Sep 1, 2024
1 parent 69cfcd9 commit fc81dc5
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 162 deletions.
177 changes: 18 additions & 159 deletions app/src/main/java/net/christianbeier/droidvnc_ng/ListenIfAdapter.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/*
* DroidVNC-NG ListenIfAdapter.
*
* Author: Christian Beier <[email protected]
* Author: elluisian <[email protected]>
*
* Copyright (C) 2020 Kitchen Armor.
* Copyright (C) 2020 Christian Beier.
*
* You can redistribute and/or modify this program under the terms of the
* GNU General Public License version 2 as published by the Free Software
Expand All @@ -20,6 +20,10 @@
*/
package net.christianbeier.droidvnc_ng;


import java.net.NetworkInterface;
import java.util.ArrayList;

import android.content.res.Resources;
import android.content.Context;
import android.util.Log;
Expand All @@ -30,118 +34,41 @@
import android.widget.Spinner;
import android.view.LayoutInflater;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.net.NetworkInterface;
import java.util.ArrayList;


public class ListenIfAdapter extends ArrayAdapter<ListenIfAdapter.NetworkInterfaceData> {
// Class representing the data to show
static class NetworkInterfaceData {
// This represents the "Any" option
public static NetworkInterfaceData ANY;


private NetworkInterface nic;
private String techName;
private String friendlyName;


public NetworkInterfaceData(ListenIfAdapter lia) {
this(null, lia);
}


public NetworkInterfaceData(NetworkInterface nic, ListenIfAdapter lia) {
this.nic = nic;

if (nic == null) {
this.techName = "0.0.0.0";
this.friendlyName = lia.getStringForAny();

} else {
this.techName = this.nic.getName();
String[] ifNameInfo = lia.extractIfInfo(this.techName);
if (ifNameInfo == null) { // No info found, consider "techName" as friendly
this.friendlyName = this.techName;

} else {
this.friendlyName = lia.getFriendlyStringForInterface(ifNameInfo[0]);
if (ifNameInfo.length > 1) {
this.friendlyName += " " + ifNameInfo[1];
}
}
}
}


public static NetworkInterfaceData getAnyOption(ListenIfAdapter lia) {
if (ANY == null) {
ANY = new NetworkInterfaceData(lia);
}
return ANY;
}


public String getName() {
return this.techName;
}


public String getFriendlyName() {
return this.friendlyName;
}


public String toString() {
return this.friendlyName + " (" + this.techName + ")";
}
}






public class ListenIfAdapter extends ArrayAdapter<NetworkInterfaceTester.NetIfData> implements NetworkInterfaceTester.OnNetworkStateChangedListener {
// This adapter uses the ViewHolder pattern
private static class ViewHolder {
public TextView txtLabel;
}

// Data to be shown with the adapter
private ArrayList<NetworkInterfaceData> data;
private ArrayList<NetworkInterfaceTester.NetIfData> data;
private int dataSize;


// Some context data for "easy retrieval"
private Context mContext;
private Resources mResources;
private LayoutInflater mInflater;




public ListenIfAdapter(ArrayList<NetworkInterface> ifs, Context context) {
public ListenIfAdapter(NetworkInterfaceTester nit, Context context) {
super(context, R.layout.spinner_row, R.id.spinner_text);

this.mContext = context;
this.mResources = this.mContext.getResources();
this.mInflater = LayoutInflater.from(this.mContext);

this.data = new ArrayList<>();
this.data.add(NetworkInterfaceData.getAnyOption(this));
for (NetworkInterface nic : ifs) {
this.data.add(new NetworkInterfaceData(nic, this));
}
this.dataSize = this.data.size();
nit.addOnNetworkStateChangedListener(this);
this.onNetworkStateChanged(nit, null, false);
}



public int getItemPositionByIfName(String ifName) {
int i = 0;
for (NetworkInterfaceData nid : this.data) {
for (NetworkInterfaceTester.NetIfData nid : this.data) {
if (nid.getName().equals(ifName)) {
return i;
}
Expand All @@ -156,7 +83,7 @@ public int getItemPositionByIfName(String ifName) {

@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) { // Check if view must be recreated, using the famous ViewHolder pattern
if (convertView == null) { // Check if view must be recreated using the famous ViewHolder pattern
convertView = this.mInflater.inflate(R.layout.spinner_row, parent, false);

ViewHolder vh = new ViewHolder();
Expand All @@ -165,99 +92,31 @@ public View getView(int position, View convertView, ViewGroup parent) {
}

ViewHolder vh = (ViewHolder)convertView.getTag();
NetworkInterfaceData nid = this.getItem(position);
NetworkInterfaceTester.NetIfData nid = this.getItem(position);
vh.txtLabel.setText(nid.toString());

return convertView;
}


@Override
public NetworkInterfaceData getItem(int position) {
public NetworkInterfaceTester.NetIfData getItem(int position) {
if (0 <= position && position < this.getCount()) {
return this.data.get(position);
}
return null;
}



@Override
public int getCount() {
return this.dataSize;
}




private String getStringForAny() {
return this.mResources.getString(R.string.main_activity_settings_listenif_spin_any);
}


/**
* Since the majority of the interfaces have standard Linux names, this method tries to get a possible friendly name.
* Special thanks go to the pages:
* - https://stackoverflow.com/questions/33747787/android-networkinterface-what-are-the-meanings-of-names-of-networkinterface
* - https://stackoverflow.com/questions/47488435/meaning-of-network-interface-rmnet-ipa0
* for some of the obscure interface names
* @param ifName name (technical) of the interface
* @return if known, a friendly name for the interface, otherwise, null
*/
private String getFriendlyStringForInterface(String ifName) {
String ifFriendlyName = null; // Null if no friendly name is known

if (ifName.equals("eth")) {
ifFriendlyName = this.mResources.getString(R.string.main_activity_settings_listenif_spin_eth);

} else if (ifName.equals("wlan")) {
ifFriendlyName = this.mResources.getString(R.string.main_activity_settings_listenif_spin_wifi);

} else if (ifName.equals("lo")) {
ifFriendlyName = this.mResources.getString(R.string.main_activity_settings_listenif_spin_lpback);

} else if (ifName.equals("tun")) {
ifFriendlyName = this.mResources.getString(R.string.main_activity_settings_listenif_spin_tun);

} else if (ifName.equals("dummy")) {
ifFriendlyName = this.mResources.getString(R.string.main_activity_settings_listenif_spin_dum);

} else if (ifName.equals("rmnet_data")) {
ifFriendlyName = this.mResources.getString(R.string.main_activity_settings_listenif_spin_rmndata);

} else if (ifName.equals("rmnet_ipa")) {
ifFriendlyName = this.mResources.getString(R.string.main_activity_settings_listenif_spin_rmnipa);

}


return ifFriendlyName;
}




/*
* This method is used to extract the name and the number of the particular interface
* from a full interface name (e.g. tun0 becomes "tun" and "0").
* Null if no info was found (id est, interface is not known)
*/
private static final String IFS_REGEX = "(eth|wlan|tun|dummy|rmnet_data|rmnet_ipa)([0-9+])";

private String[] extractIfInfo(String ifName) {
Pattern pt = Pattern.compile(IFS_REGEX, Pattern.CASE_INSENSITIVE);
Matcher mc = pt.matcher(ifName);

if (mc.matches()) {
return new String[] { mc.group(1), mc.group(2) };
}

// If not found, check for loopback
if (ifName.equalsIgnoreCase("lo")) {
return new String[] { "lo" };
}

// No useful info was found
return null;
public void onNetworkStateChanged(NetworkInterfaceTester nit, NetworkInterface iface, boolean enabled) {
this.data = nit.getAvailableInterfaces();
this.dataSize = this.data.size();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -311,13 +311,14 @@ protected void onCreate(Bundle savedInstanceState) {
});


ListenIfAdapter lsif = new ListenIfAdapter(Utils.getAvailableNICs(), this);
NetworkInterfaceTester nit = new NetworkInterfaceTester(this);
ListenIfAdapter lsif = new ListenIfAdapter(nit, this);
final Spinner listenInterfaceSpin = findViewById(R.id.settings_listening_interface);
listenInterfaceSpin.setAdapter(lsif);
listenInterfaceSpin.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
ListenIfAdapter.NetworkInterfaceData d = (ListenIfAdapter.NetworkInterfaceData)parent.getItemAtPosition(pos);
NetworkInterfaceTester.NetIfData d = (NetworkInterfaceTester.NetIfData)parent.getItemAtPosition(pos);
if(!(prefs.getString(Constants.PREFS_KEY_SETTINGS_LISTEN_INTERFACE, null) == null && d.getName().equals(mDefaults.getListenInterface()))) {
SharedPreferences.Editor ed = prefs.edit();
ed.putString(Constants.PREFS_KEY_SETTINGS_LISTEN_INTERFACE, d.getName());
Expand All @@ -337,6 +338,7 @@ public void onNothingSelected(AdapterView<?> parent) {




final EditText port = findViewById(R.id.settings_port);
if(prefs.getInt(Constants.PREFS_KEY_SETTINGS_PORT, mDefaults.getPort()) < 0) {
port.setHint(R.string.main_activity_settings_port_not_listening);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,7 @@ static boolean isServerActive() {
}



/**
* This returns A SINGLE ipv4 address for the selected interface... giving the possibility
* to the server to listen to that address only.
Expand Down Expand Up @@ -816,7 +817,7 @@ static ArrayList<String> getReachableIPv4s() {
}
} else {
// Single interface: get all its IPv4 addresses
ArrayList<String> ipv4s = Utils.getIPv4ForInterface(NetworkInterface.getByName(listenInterface));
ArrayList<String> ipv4s = Utils.getIPv4ForInterface(listenInterface);
for (String ipv4 : ipv4s) {
hosts.add(ipv4);
}
Expand Down
Loading

0 comments on commit fc81dc5

Please sign in to comment.