Improve P2P connectivity

This commit is contained in:
Daniel Pollithy 2018-01-08 00:49:52 +01:00
parent 01646644d1
commit eb7f131171
10 changed files with 207 additions and 56 deletions

View File

@ -103,22 +103,7 @@ public class ChatActivity extends AppCompatActivity {
private void connectToPeer(String address) {
if (mBound) {
mService.connect(address, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Toast.makeText(getApplicationContext(), "Connected to peer", Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(int reason) {
Toast.makeText(getApplicationContext(), "Error connecting to peer", Toast.LENGTH_SHORT).show();
}
});
} else {
Toast.makeText(getApplicationContext(), "Service not available", Toast.LENGTH_SHORT).show();
}
}
private void initUI() { private void initUI() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);

View File

@ -21,6 +21,7 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ListView; import android.widget.ListView;
import android.widget.Toast;
import com.flashwifi.wifip2p.datastore.PeerInformation; import com.flashwifi.wifip2p.datastore.PeerInformation;
import com.flashwifi.wifip2p.datastore.PeerListAdapter; import com.flashwifi.wifip2p.datastore.PeerListAdapter;
@ -45,6 +46,9 @@ public class SearchFragment extends Fragment {
ArrayList<String> arrayList; ArrayList<String> arrayList;
PeerListAdapter peerListAdapter; PeerListAdapter peerListAdapter;
View view;
private boolean busy = false;
public SearchFragment() { public SearchFragment() {
// Empty constructor required for fragment subclasses // Empty constructor required for fragment subclasses
@ -89,11 +93,15 @@ public class SearchFragment extends Fragment {
return f; return f;
} }
private void updateUi(Intent intent) { private void updateList() {
peerListAdapter.notifyDataSetInvalidated(); peerListAdapter.notifyDataSetInvalidated();
peerListAdapter.clear(); peerListAdapter.clear();
peerListAdapter.addAll(PeerStore.getInstance().getPeerArrayList()); peerListAdapter.addAll(PeerStore.getInstance().getPeerArrayList());
peerListAdapter.notifyDataSetChanged(); peerListAdapter.notifyDataSetChanged();
}
private void updateUi(Intent intent) {
updateList();
String what = intent.getStringExtra("what"); String what = intent.getStringExtra("what");
Log.d(">>>>>>>>>>>>", "updateUi: " + what); Log.d(">>>>>>>>>>>>", "updateUi: " + what);
@ -176,6 +184,8 @@ public class SearchFragment extends Fragment {
Intent intent = new Intent(getActivity(), WiFiDirectBroadcastService.class); Intent intent = new Intent(getActivity(), WiFiDirectBroadcastService.class);
getActivity().bindService(intent, mConnection, Context.BIND_AUTO_CREATE); getActivity().bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
view = getActivity().findViewById(R.id.main_view);
initUI(); initUI();
} }
@ -205,20 +215,39 @@ public class SearchFragment extends Fragment {
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override @Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
if (!busy) {
busy = true;
PeerInformation peer = PeerStore.getInstance().getPeerArrayList().get(i); PeerInformation peer = PeerStore.getInstance().getPeerArrayList().get(i);
peer.setSelected(true);
updateList();
String address = peer.getWifiP2pDevice().deviceAddress; String address = peer.getWifiP2pDevice().deviceAddress;
String name = peer.getWifiP2pDevice().deviceName; String name = peer.getWifiP2pDevice().deviceName;
startChat(address, name); startChat(address, name);
} else {
Toast.makeText(view.getContext(), "Busy", Toast.LENGTH_SHORT).show();
}
} }
}); });
} }
public void startChat(String address, String name) { public void startChat(final String address, String name) {
// start the socket for the negotiation mService.connect(address, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Toast.makeText(view.getContext(), "Connected to peer", Toast.LENGTH_SHORT).show();
// start the protocol
startNegotiationProtocol(address); startNegotiationProtocol(address);
busy = false;
}
@Override
public void onFailure(int reason) {
Toast.makeText(view.getContext(), "Error connecting to peer", Toast.LENGTH_SHORT).show();
busy = false;
}
});
/*Intent intent = new Intent(getActivity(), ChatActivity.class); /*Intent intent = new Intent(getActivity(), ChatActivity.class);
intent.putExtra("address", address); intent.putExtra("address", address);
@ -227,7 +256,7 @@ public class SearchFragment extends Fragment {
} }
public void onRefreshButtonClick() { public void onRefreshButtonClick() {
final View view = getActivity().findViewById(R.id.main_view);
if (mBound) { if (mBound) {
mService.getPeerList(new WifiP2pManager.ActionListener() { mService.getPeerList(new WifiP2pManager.ActionListener() {
@Override @Override

View File

@ -5,19 +5,28 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.p2p.WifiP2pConfig; import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice; import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pGroup; import android.net.wifi.p2p.WifiP2pGroup;
import android.net.wifi.p2p.WifiP2pInfo; import android.net.wifi.p2p.WifiP2pInfo;
import android.net.wifi.p2p.WifiP2pManager; import android.net.wifi.p2p.WifiP2pManager;
import android.os.AsyncTask;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.util.Log; import android.util.Log;
import android.widget.Toast;
import com.flashwifi.wifip2p.WalletAddressAndBalanceChecker;
import com.flashwifi.wifip2p.negotiation.Negotiator;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random; import java.util.Random;
public class WiFiDirectBroadcastService extends Service { public class WiFiDirectBroadcastService extends Service {
@ -49,21 +58,74 @@ public class WiFiDirectBroadcastService extends Service {
// discovery mode // discovery mode
private boolean discoveryModeActive = false; private boolean discoveryModeActive = false;
public void startNegotiationServer(boolean isClient, String macAddress) { public String getWFDMacAddress(){
Log.d("", "startSocketServer: "); try {
//negotiationServerTask = new NegotiationServerTask(); List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
//negotiationServerTask.execute(); for (NetworkInterface ntwInterface : interfaces) {
String isClientString = (isClient) ? "True" : "False";
// ToDo: rewire this if (ntwInterface.getName().equalsIgnoreCase("p2p0")) {
// new NegotiationServerTask().execute(isClientString, macAddress); byte[] byteMac = ntwInterface.getHardwareAddress();
if (byteMac==null){
return null;
}
StringBuilder strBuilder = new StringBuilder();
for (int i=0; i<byteMac.length; i++) {
strBuilder.append(String.format("%02X:", byteMac[i]));
} }
public void startNegotiationClient(InetAddress address, boolean isClient, String macAddress) { if (strBuilder.length()>0){
Log.d("", "startSocketClient: "); strBuilder.deleteCharAt(strBuilder.length()-1);
String isClientString = (isClient) ? "True" : "False"; }
String ipaddr = address.getHostAddress();
// ToDo: use the Negotiator here return strBuilder.toString();
// new NegotiationClientTask().execute(isClientString, ipaddr, macAddress); }
}
} catch (Exception e) {
Log.d(TAG, e.getMessage());
}
return null;
}
public void startNegotiationServer(final boolean isClient, String macAddress) {
AsyncTask.execute(new Runnable() {
@Override
public void run() {
Negotiator negotiator = new Negotiator(isClient, getWFDMacAddress());
// ToDo: run as long as this group is connected
while (true) {
negotiator.workAsServer();
deletePersistentGroups();
sendUpdateUIBroadcast();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
public void startNegotiationClient(final InetAddress address, final boolean isClient, String macAddress) {
AsyncTask.execute(new Runnable() {
@Override
public void run() {
Negotiator negotiator = new Negotiator(isClient, getWFDMacAddress());
// ToDo: run as long as this group is connected
while (true) {
negotiator.workAsClient(address.getHostAddress());
deletePersistentGroups();
sendUpdateUIBroadcast();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
} }
public WifiP2pInfo getP2p_info() { public WifiP2pInfo getP2p_info() {

View File

@ -16,6 +16,7 @@ public class PeerInformation {
private WifiP2pInfo p2pInfo; private WifiP2pInfo p2pInfo;
private WifiP2pDevice wifiP2pDevice; private WifiP2pDevice wifiP2pDevice;
private Date lastUpdate; private Date lastUpdate;
private boolean selected;
// age stores how long it has been since the last signal from this peer // age stores how long it has been since the last signal from this peer
// it is not stored in seconds but in update cycles // it is not stored in seconds but in update cycles
@ -26,6 +27,7 @@ public class PeerInformation {
private NegotiationFinalization latestFinalization; private NegotiationFinalization latestFinalization;
public PeerInformation() { public PeerInformation() {
selected = false;
age = 0; age = 0;
} }
@ -76,4 +78,12 @@ public class PeerInformation {
public void setIPAddress(String IPAddress) { public void setIPAddress(String IPAddress) {
this.ipAddress = IPAddress; this.ipAddress = IPAddress;
} }
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
} }

View File

@ -6,6 +6,7 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.TableRow;
import android.widget.TextView; import android.widget.TextView;
import com.flashwifi.wifip2p.R; import com.flashwifi.wifip2p.R;
@ -42,6 +43,15 @@ public class PeerListAdapter extends ArrayAdapter<PeerInformation> {
TextView tt3 = (TextView) v.findViewById(R.id.description); TextView tt3 = (TextView) v.findViewById(R.id.description);
TextView tt4 = (TextView) v.findViewById(R.id.ipAddr); TextView tt4 = (TextView) v.findViewById(R.id.ipAddr);
TextView tt5 = (TextView) v.findViewById(R.id.iotaPrice); TextView tt5 = (TextView) v.findViewById(R.id.iotaPrice);
TableRow row = (TableRow) v.findViewById(R.id.talkingRow);
if (row != null) {
if (p.isSelected()) {
row.setVisibility(View.VISIBLE);
} else {
row.setVisibility(View.INVISIBLE);
}
}
WifiP2pDevice device = p.getWifiP2pDevice(); WifiP2pDevice device = p.getWifiP2pDevice();
if (device != null) { if (device != null) {
@ -69,6 +79,8 @@ public class PeerListAdapter extends ArrayAdapter<PeerInformation> {
} }
return v; return v;
} }

View File

@ -37,16 +37,18 @@ public class PeerStore {
*/ */
public boolean updateOrCreate(PeerInformation peer) { public boolean updateOrCreate(PeerInformation peer) {
String macAddress = peer.getWifiP2pDevice().deviceAddress; String macAddress = peer.getWifiP2pDevice().deviceAddress;
boolean created = peers.containsKey(macAddress); boolean exists = peers.containsKey(macAddress);
if (!created) { if (exists) {
// Temp store for the important values // Temp store for the important values
peer.setSelected(peers.get(macAddress).isSelected());
} }
// overwrite or insert // overwrite or insert
peers.put(macAddress, peer); peers.put(macAddress, peer);
return created;
return !exists;
} }
public ArrayList<PeerInformation> getPeerArrayList() { public ArrayList<PeerInformation> getPeerArrayList() {
@ -71,6 +73,7 @@ public class PeerStore {
} }
private PeerInformation getOrCreatePeer(String address_) { private PeerInformation getOrCreatePeer(String address_) {
address_ = address_.toLowerCase();
if (peers.containsKey(address_)) { if (peers.containsKey(address_)) {
return peers.get(address_); return peers.get(address_);
} }

View File

@ -19,7 +19,9 @@ import java.net.SocketTimeoutException;
public class Negotiator { public class Negotiator {
private static final String TAG = "Negotiator"; private static final String TAG = "Negotiator";
private static final int PORT = 9898; private static final int PORT = 9898;
private static final int timeoutMillis = 1000; private static final int clientTimeoutMillis = 100000;
private static final int serverTimeoutMillis = 100000;
private final String ownMacAddress;
private SocketWrapper socketWrapper; private SocketWrapper socketWrapper;
@ -56,9 +58,11 @@ public class Negotiator {
ERROR ERROR
} }
public Negotiator(boolean isConsumer) { public Negotiator(boolean isConsumer, String ownMacAddress) {
this.isConsumer = isConsumer; this.isConsumer = isConsumer;
gson = new GsonBuilder().create(); gson = new GsonBuilder().create();
this.ownMacAddress = ownMacAddress;
Log.d(TAG, "Negotiator: " + ownMacAddress);
} }
public boolean workAsClient(String serverIPAddress) { public boolean workAsClient(String serverIPAddress) {
@ -70,14 +74,14 @@ public class Negotiator {
try { try {
// create client socket that connects to server // create client socket that connects to server
socket = new Socket(serverIPAddress, PORT); socket = new Socket(serverIPAddress, PORT);
socket.setSoTimeout(timeoutMillis); socket.setSoTimeout(clientTimeoutMillis);
Log.d(TAG, "workAsClient: client socket created"); Log.d(TAG, "workAsClient: client socket created");
// wrap the socket // wrap the socket
socketWrapper = new SocketWrapper(socket); socketWrapper = new SocketWrapper(socket);
// send Client Request // send Client Request
String hello = isConsumer ? "HELLO I AM CLIENT" : "HELLO I AM SERVER"; String hello = isClient ? "HELLO I AM CLIENT" : "HELLO I AM SERVER";
socketWrapper.sendLine(hello); socketWrapper.sendLine(hello);
// Whether we want to provide a hotspot or use one // Whether we want to provide a hotspot or use one
@ -113,12 +117,12 @@ public class Negotiator {
try { try {
// use the port to start // use the port to start
serverSocket = new ServerSocket(PORT); serverSocket = new ServerSocket(PORT);
serverSocket.setSoTimeout(timeoutMillis); //serverSocket.setSoTimeout(serverTimeoutMillis);
Log.d(TAG, "doInBackground: Server is waiting for connection"); Log.d(TAG, "doInBackground: Server is waiting for connection");
// accept one connection // accept one connection
socket = serverSocket.accept(); socket = serverSocket.accept();
socket.setSoTimeout(timeoutMillis); //socket.setSoTimeout(serverTimeoutMillis);
// wrap the socket // wrap the socket
socketWrapper = new SocketWrapper(socket); socketWrapper = new SocketWrapper(socket);
@ -126,9 +130,14 @@ public class Negotiator {
// WAIT FOR CLIENT // WAIT FOR CLIENT
String hello = socketWrapper.getLine(); String hello = socketWrapper.getLine();
if (hello == null) {
error(0, "no hello received");
return false;
}
// Check: Is the peer in the same role as we are // Check: Is the peer in the same role as we are
// server and server or client and client MAKES NO SENSE // server and server or client and client MAKES NO SENSE
if (hello.contains("SERVER") && !isClient || hello.contains("CLIENT") && isClient) { if (hello.contains("SERVER") && !isClient || hello.contains("CLIENT") && isClient){
error(1, "Pairing roles are broken"); error(1, "Pairing roles are broken");
return false; return false;
} }
@ -176,8 +185,9 @@ public class Negotiator {
// CHECK OFFER // CHECK OFFER
consumer_state = ConsumerState.CHECK_OFFER; consumer_state = ConsumerState.CHECK_OFFER;
NegotiationOffer offer = gson.fromJson(offerString, NegotiationOffer.class); NegotiationOffer offer = gson.fromJson(offerString, NegotiationOffer.class);
String otherMac = offer.getHotspotMac();
// Write offer to the PeerStore // Write offer to the PeerStore
PeerStore.getInstance().setLatestOffer(ipAddress, offer); PeerStore.getInstance().setLatestOffer(otherMac, offer);
// ToDo: implement accept or deny logic // ToDo: implement accept or deny logic
if (!true) { if (!true) {
@ -187,7 +197,7 @@ public class Negotiator {
// SEND NegotiationAnswer // SEND NegotiationAnswer
// ToDo: where shall the input come from? // ToDo: where shall the input come from?
NegotiationOfferAnswer answer = new NegotiationOfferAnswer(true, 10); NegotiationOfferAnswer answer = new NegotiationOfferAnswer(true, 10, ownMacAddress);
String answerString = gson.toJson(answer); String answerString = gson.toJson(answer);
socketWrapper.sendLine(answerString); socketWrapper.sendLine(answerString);
@ -202,7 +212,7 @@ public class Negotiator {
NegotiationFinalization finalization = gson.fromJson(finalizationString, NegotiationFinalization.class); NegotiationFinalization finalization = gson.fromJson(finalizationString, NegotiationFinalization.class);
// Write offer to the PeerStore // Write offer to the PeerStore
PeerStore.getInstance().setLatestFinalization(ipAddress, finalization); PeerStore.getInstance().setLatestFinalization(otherMac, finalization);
// Send OK // Send OK
@ -220,7 +230,8 @@ public class Negotiator {
hotspot_state = HotspotState.CHECK_CLIENT_REQUEST; hotspot_state = HotspotState.CHECK_CLIENT_REQUEST;
// send offer // send offer
NegotiationOffer offer = new NegotiationOffer(1, 100, 0); int iotaPerMegabyte = (int) (Math.random() * (1000 - 10)) + 10;
NegotiationOffer offer = new NegotiationOffer(1, 100, iotaPerMegabyte, ownMacAddress);
String offerString = gson.toJson(offer); String offerString = gson.toJson(offer);
socketWrapper.sendLine(offerString); socketWrapper.sendLine(offerString);
@ -228,9 +239,15 @@ public class Negotiator {
hotspot_state = HotspotState.WAIT_FOR_ANSWER; hotspot_state = HotspotState.WAIT_FOR_ANSWER;
String answerString = socketWrapper.getLine(); String answerString = socketWrapper.getLine();
if (answerString == null) {
error(8, "No answer received");
return false;
}
// Parse the answer // Parse the answer
NegotiationOfferAnswer answer = gson.fromJson(answerString, NegotiationOfferAnswer.class); NegotiationOfferAnswer answer = gson.fromJson(answerString, NegotiationOfferAnswer.class);
PeerStore.getInstance().setLatestOfferAnswer(ipAddress, answer); String otherMac = answer.getConsumerMac();
PeerStore.getInstance().setLatestOfferAnswer(otherMac, answer);
// CHECK_ANSWER // CHECK_ANSWER
hotspot_state = HotspotState.CHECK_ANSWER; hotspot_state = HotspotState.CHECK_ANSWER;

View File

@ -6,12 +6,14 @@ public class NegotiationOffer {
private int minMinutes; private int minMinutes;
private int maxMinutes; private int maxMinutes;
private int iotaPerMegabyte; private int iotaPerMegabyte;
private String hotspotMac;
public NegotiationOffer(int minMinutes, int maxMinutes, int iotaPerMegabyte) { public NegotiationOffer(int minMinutes, int maxMinutes, int iotaPerMegabyte, String hotspotMac) {
this.type = "offer"; this.type = "offer";
this.minMinutes = minMinutes; this.minMinutes = minMinutes;
this.maxMinutes = maxMinutes; this.maxMinutes = maxMinutes;
this.iotaPerMegabyte = iotaPerMegabyte; this.iotaPerMegabyte = iotaPerMegabyte;
this.hotspotMac = hotspotMac;
} }
public String getType() { public String getType() {
@ -29,4 +31,8 @@ public class NegotiationOffer {
public int getIotaPerMegabyte() { public int getIotaPerMegabyte() {
return iotaPerMegabyte; return iotaPerMegabyte;
} }
public String getHotspotMac() {
return hotspotMac;
}
} }

View File

@ -5,11 +5,13 @@ public class NegotiationOfferAnswer {
private String type; private String type;
private boolean agreeToConditions; private boolean agreeToConditions;
private int duranceInMinutes; private int duranceInMinutes;
private String consumerMac;
public NegotiationOfferAnswer(boolean agreeToConditions, int duranceInMinutes) { public NegotiationOfferAnswer(boolean agreeToConditions, int duranceInMinutes, String consumerMac) {
this.type = "answerToOffer"; this.type = "answerToOffer";
this.agreeToConditions = agreeToConditions; this.agreeToConditions = agreeToConditions;
this.duranceInMinutes = duranceInMinutes; this.duranceInMinutes = duranceInMinutes;
this.consumerMac = consumerMac;
} }
public String getType() { public String getType() {
@ -23,4 +25,8 @@ public class NegotiationOfferAnswer {
public int getDuranceInMinutes() { public int getDuranceInMinutes() {
return duranceInMinutes; return duranceInMinutes;
} }
public String getConsumerMac() {
return consumerMac;
}
} }

View File

@ -61,5 +61,26 @@
</TableRow> </TableRow>
<TableRow
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="invisible"
android:id="@+id/talkingRow">
<ProgressBar
style="?android:attr/progressBarStyle"
android:layout_width="63dp"
android:layout_height="match_parent" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Stop Talking" />
</TableRow>
</TableLayout> </TableLayout>