From ca6beaf0b8c7f86feabc6a0b960697e75955412d Mon Sep 17 00:00:00 2001 From: Mark Raymond Jr Date: Sun, 25 Oct 2015 20:44:38 -0500 Subject: [PATCH] Some small bug fixes and cleanups. --- .../BackgroundClientRegistrationJob.java | 14 +- .../com/peak/salut/BackgroundDataJob.java | 2 +- .../BackgroundServerRegistrationJob.java | 3 +- src/main/java/com/peak/salut/Salut.java | 183 ++++++++++-------- .../peak/salut/SalutBroadcastReciever.java | 21 +- .../com/peak/salut/SalutDataReceiver.java | 7 +- 6 files changed, 135 insertions(+), 95 deletions(-) diff --git a/src/main/java/com/peak/salut/BackgroundClientRegistrationJob.java b/src/main/java/com/peak/salut/BackgroundClientRegistrationJob.java index 3f720f0..cbbfdd5 100644 --- a/src/main/java/com/peak/salut/BackgroundClientRegistrationJob.java +++ b/src/main/java/com/peak/salut/BackgroundClientRegistrationJob.java @@ -70,7 +70,7 @@ public void doOnBackground() { Log.d(Salut.TAG, "Registered Host | " + salutInstance.registeredHost.deviceName); salutInstance.thisDevice.isRegistered = true; - salutInstance.dataReceiver.currentContext.runOnUiThread(new Runnable() { + salutInstance.dataReceiver.activity.runOnUiThread(new Runnable() { @Override public void run() { if (onRegistered != null) @@ -86,13 +86,12 @@ public void run() { salutInstance.thisDevice.isRegistered = false; salutInstance.registeredHost = null; - salutInstance.cleanUpDataConnection(false); - salutInstance.cleanUpDeviceConnection(false); + salutInstance.closeDataSocket(); salutInstance.disconnectFromDevice(); if(onUnregisterSuccess != null) //Success Callback. { - salutInstance.dataReceiver.currentContext.runOnUiThread(new Runnable() { + salutInstance.dataReceiver.activity.runOnUiThread(new Runnable() { @Override public void run() { onUnregisterSuccess.call(); @@ -110,8 +109,10 @@ public void run() { } catch (IOException ex) { + ex.printStackTrace(); + Log.e(Salut.TAG, "An error occurred while attempting to register or unregister."); - salutInstance.dataReceiver.currentContext.runOnUiThread(new Runnable() { + salutInstance.dataReceiver.activity.runOnUiThread(new Runnable() { @Override public void run() { if (onRegistrationFail != null && !salutInstance.thisDevice.isRegistered) //Prevents both callbacks from being called. @@ -133,9 +134,8 @@ public void run() { if(disableWiFiOnUnregister) { - Salut.disableWiFi(salutInstance.dataReceiver.currentContext); + Salut.disableWiFi(salutInstance.dataReceiver.activity); } - try { registrationSocket.close(); diff --git a/src/main/java/com/peak/salut/BackgroundDataJob.java b/src/main/java/com/peak/salut/BackgroundDataJob.java index a8634c2..004087b 100644 --- a/src/main/java/com/peak/salut/BackgroundDataJob.java +++ b/src/main/java/com/peak/salut/BackgroundDataJob.java @@ -36,7 +36,7 @@ public void doOnBackground() { if(!data.isEmpty()) { - salutInstance.dataReceiver.currentContext.runOnUiThread(new Runnable() { + salutInstance.dataReceiver.activity.runOnUiThread(new Runnable() { @Override public void run() { salutInstance.dataReceiver.dataCallback.onDataReceived(data); diff --git a/src/main/java/com/peak/salut/BackgroundServerRegistrationJob.java b/src/main/java/com/peak/salut/BackgroundServerRegistrationJob.java index ef7c5e3..d4e8607 100644 --- a/src/main/java/com/peak/salut/BackgroundServerRegistrationJob.java +++ b/src/main/java/com/peak/salut/BackgroundServerRegistrationJob.java @@ -55,7 +55,7 @@ public void doOnBackground() { salutInstance.registeredClients.add(clientDevice); if (salutInstance.onDeviceRegisteredWithHost != null) { - salutInstance.dataReceiver.currentContext.runOnUiThread(new Runnable() { + salutInstance.dataReceiver.activity.runOnUiThread(new Runnable() { @Override public void run() { salutInstance.onDeviceRegisteredWithHost.call(finalDevice); @@ -84,6 +84,7 @@ public void run() { toClient.close(); } catch (Exception ex) { + ex.printStackTrace(); Log.e(Salut.TAG, "An error occurred while dealing with registration for a client."); } finally { diff --git a/src/main/java/com/peak/salut/Salut.java b/src/main/java/com/peak/salut/Salut.java index cf7f407..d071f9e 100644 --- a/src/main/java/com/peak/salut/Salut.java +++ b/src/main/java/com/peak/salut/Salut.java @@ -22,11 +22,11 @@ import com.peak.salut.Callbacks.SalutDeviceCallback; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; -import java.net.SocketException; import java.util.ArrayList; import java.util.Map; @@ -50,6 +50,7 @@ public class Salut implements WifiP2pManager.ConnectionInfoListener{ private SalutCallback deviceNotSupported; protected boolean registrationIsRunning = false; protected SalutDeviceCallback onDeviceRegisteredWithHost; + protected SalutCallback unexpectedDisconnect; public SalutDevice thisDevice; public SalutDevice registeredHost; @@ -74,9 +75,9 @@ public class Salut implements WifiP2pManager.ConnectionInfoListener{ - public Salut(SalutDataReceiver dataReceiver, SalutServiceData salutServiceData,SalutCallback deviceNotSupported) + public Salut(SalutDataReceiver dataReceiver, SalutServiceData salutServiceData, SalutCallback deviceNotSupported) { - WifiManager wifiMan = (WifiManager) dataReceiver.currentContext.getSystemService(Context.WIFI_SERVICE); + WifiManager wifiMan = (WifiManager) dataReceiver.context.getSystemService(Context.WIFI_SERVICE); WifiInfo wifiInfo = wifiMan.getConnectionInfo(); this.dataReceiver = dataReceiver; @@ -99,18 +100,15 @@ public Salut(SalutDataReceiver dataReceiver, SalutServiceData salutServiceData,S intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION); - manager = (WifiP2pManager) dataReceiver.currentContext.getSystemService(Context.WIFI_P2P_SERVICE); - channel = manager.initialize(dataReceiver.currentContext, dataReceiver.currentContext.getMainLooper(), new WifiP2pManager.ChannelListener() { + manager = (WifiP2pManager) dataReceiver.context.getSystemService(Context.WIFI_P2P_SERVICE); + channel = manager.initialize(dataReceiver.context, dataReceiver.context.getMainLooper(), new WifiP2pManager.ChannelListener() { @Override public void onChannelDisconnected() { Log.d(TAG, "Attempting to reinitialize channel."); - channel = manager.initialize(Salut.this.dataReceiver.currentContext,Salut.this.dataReceiver.currentContext.getMainLooper(), this); + channel = manager.initialize(Salut.this.dataReceiver.context,Salut.this.dataReceiver.context.getMainLooper(), this); } }); - obtainSalutPortLock(); - obtainServicePortLock(); - receiver = new SalutBroadcastReciever(this, manager, channel); } @@ -191,27 +189,25 @@ public void onConnectionInfoAvailable(final WifiP2pInfo info) { * client socket for every client. This is handled by the registration jobs. * This will automatically handle first time connections.*/ - if (isRunningAsHost && !registrationIsRunning) { - manager.requestGroupInfo(channel, new WifiP2pManager.GroupInfoListener() { - @Override - public void onGroupInfoAvailable(WifiP2pGroup group) { - if (group.getClientList().isEmpty()) { - return; - } else { + manager.requestGroupInfo(channel, new WifiP2pManager.GroupInfoListener() { + @Override + public void onGroupInfoAvailable(WifiP2pGroup group) { + + if (isRunningAsHost && !registrationIsRunning) { + if (info.groupFormed && !group.getClientList().isEmpty()) { startHostRegistrationServer(); } + } else if (!thisDevice.isRegistered && !info.isGroupOwner) { + if (serviceRequest == null) { + //This means that discoverNetworkServices was never called and we're still connected to an old host for some reason. + Log.e(Salut.TAG, "This device is still connected to an old host for some reason. A forced disconnect will be attempted."); + forceDisconnect(); + } + Log.v(Salut.TAG, "Successfully connected to another device."); + startRegistrationForClient(new InetSocketAddress(info.groupOwnerAddress.getHostAddress(), SALUT_SERVER_PORT)); } - }); - } - else if(!thisDevice.isRegistered && !info.isGroupOwner) { - if(info.groupOwnerAddress == null || info.groupOwnerAddress.getHostAddress().isEmpty()) - { - disconnectFromDevice(); - return; } - - startRegistrationForClient(new InetSocketAddress(info.groupOwnerAddress.getHostAddress(), SALUT_SERVER_PORT)); - } + }); } public static void enableWiFi(Context context) @@ -256,25 +252,24 @@ public static boolean hotspotIsEnabled(Context context) return false; } - protected void cleanUpDeviceConnection(boolean reopenPorts) + protected void closeRegistrationSocket() { try { - salutServerSocket.close(); - if(isRunningAsHost) + if(registrationIsRunning) { + salutServerSocket.close(); Log.v(TAG, "Registration sockets now closed."); } } catch (Exception ex) { - Log.e(TAG, "Failed to close one or more sockets. Perhaps they were already closed or null?"); + Log.e(TAG, "Failed to close registration socket."); } - if(reopenPorts) - obtainSalutPortLock(); + registrationIsRunning = false; } - protected void cleanUpDataConnection(boolean reopenPorts) + protected void closeDataSocket() { try { listenerServiceSocket.close(); @@ -282,11 +277,8 @@ protected void cleanUpDataConnection(boolean reopenPorts) } catch (Exception ex) { - Log.e(TAG, "Failed to close one or more sockets. Perhaps they were already closed or null."); + Log.e(TAG, "Failed to close listening socket."); } - - if(reopenPorts) - obtainServicePortLock(); } private void startRegistrationForClient(final InetSocketAddress hostDeviceAddress) @@ -305,6 +297,8 @@ private void sendData(final SalutDevice device, final Object data, @Nullable fin private void startHostRegistrationServer() { + obtainSalutPortLock(); + AsyncJob.doInBackground(new AsyncJob.OnBackgroundJob() { @Override public void doOnBackground() { @@ -320,15 +314,10 @@ public void doOnBackground() { AsyncJob.doInBackground(registrationJob); } - } catch (Exception ex) { - if (ex instanceof SocketException) { - Log.d(TAG, "Successfully shutdown socket."); - } else { - Log.e(TAG, "An error occurred while executing a server thread."); - ex.printStackTrace(); - } - } finally { registrationIsRunning = false; + } catch (Exception ex) { + Log.e(TAG, "An error has occurred within the registration server thread."); + ex.printStackTrace(); } } }); @@ -336,6 +325,8 @@ public void doOnBackground() { protected void startListeningForData() { + obtainServicePortLock(); + AsyncJob.doInBackground(new AsyncJob.OnBackgroundJob() { @Override public void doOnBackground() { @@ -345,7 +336,7 @@ public void doOnBackground() { while (isRunningAsHost || thisDevice.isRegistered) { - Log.d(TAG, "Listening for service data..."); + Log.d(TAG, "\nListening for service data..."); Socket dataListener = listenerServiceSocket.accept(); BackgroundDataJob dealWithData = new BackgroundDataJob(Salut.this, dataListener); @@ -354,12 +345,8 @@ public void doOnBackground() { } } catch (Exception ex) { - if (ex instanceof SocketException) { - Log.d(TAG, "Successfully shutdown socket."); - } else { - Log.e(TAG, "An error occurred while executing a server thread."); + Log.e(TAG, "An error has occurred within the data listening server thread."); ex.printStackTrace(); - } } } }); @@ -369,6 +356,7 @@ public void registerWithHost(final SalutDevice device, @Nullable SalutCallback o { BackgroundClientRegistrationJob.onRegistered = onRegistered; BackgroundClientRegistrationJob.onRegistrationFail = onRegistrationFail; + this.unexpectedDisconnect = onRegistrationFail; connectToDevice(device, onRegistrationFail); } @@ -417,19 +405,20 @@ public void onFailure(int reason) { } }); - stopServiceDiscovery(); + stopServiceDiscovery(true); connectingIsCanceled = true; } private void connectToDevice(final SalutDevice device, final SalutCallback onFailure) { + WifiP2pConfig config = new WifiP2pConfig(); config.deviceAddress = device.macAddress; manager.connect(channel, config, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { - Log.d(TAG, "Successfully connected to another device."); + Log.d(TAG, "Attempting to connect to another device."); lastConnectedDevice = device; } @@ -441,16 +430,55 @@ public void onFailure(int reason) { }); } + private void deleteGroup(WifiP2pManager manager, WifiP2pManager.Channel channel, WifiP2pGroup wifiP2pGroup) + { + try { + Method getNetworkId = WifiP2pGroup.class.getMethod("getNetworkId"); + Integer networkId = (Integer) getNetworkId.invoke(wifiP2pGroup); + Method deletePersistentGroup = WifiP2pManager.class.getMethod("deletePersistentGroup", + WifiP2pManager.Channel.class, Integer.class, WifiP2pManager.ActionListener.class); + deletePersistentGroup.invoke(manager, channel, networkId, null); + } catch (NoSuchMethodException e) { + Log.v(Salut.TAG, "Failed to delete persistent group.", e); + } catch (InvocationTargetException e) { + Log.v(Salut.TAG, "Failed to delete persistent group.", e); + } catch (IllegalAccessException e) { + Log.v(Salut.TAG, "Failed to delete persistent group.", e); + } + } + + protected void forceDisconnect() + { + WifiP2pManager.ActionListener doNothing = new WifiP2pManager.ActionListener() { + @Override + public void onSuccess() { + + } + + @Override + public void onFailure(int reason) { + + } + }; + + stopServiceDiscovery(false); + manager.cancelConnect(channel, doNothing); + manager.clearLocalServices(channel, doNothing); + manager.clearServiceRequests(channel, doNothing); + manager.stopPeerDiscovery(channel, doNothing); + } + protected void disconnectFromDevice() { manager.requestGroupInfo(channel, new WifiP2pManager.GroupInfoListener() { @Override - public void onGroupInfoAvailable(WifiP2pGroup group) { + public void onGroupInfoAvailable(final WifiP2pGroup group) { if (group != null) { manager.removeGroup(channel, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { isConnectedToAnotherDevice = false; + deleteGroup(manager, channel, group); Log.d(TAG, "Removed WiFi Direct Group."); } @@ -518,22 +546,21 @@ public void unregisterClient(@Nullable SalutCallback onSuccess, @Nullable SalutC if(receiverRegistered) { - dataReceiver.currentContext.unregisterReceiver(receiver); + dataReceiver.context.unregisterReceiver(receiver); receiverRegistered = false; } if(!isConnectedToAnotherDevice) { Log.d(TAG, "Attempted to unregister, but not connected to group. The remote service may already have shutdown."); + thisDevice.isRegistered = false; + registeredHost = null; + closeDataSocket(); + disconnectFromDevice(); if(onSuccess != null) { onSuccess.call(); } - thisDevice.isRegistered = false; - registeredHost = null; - cleanUpDataConnection(false); - cleanUpDeviceConnection(false); - disconnectFromDevice(); } else { @@ -562,7 +589,7 @@ public void startNetworkService(@Nullable SalutDeviceCallback onDeviceRegistered if(!receiverRegistered) { - dataReceiver.currentContext.registerReceiver(receiver, intentFilter); + dataReceiver.context.registerReceiver(receiver, intentFilter); receiverRegistered = true; } @@ -724,14 +751,15 @@ public void run() { if(connectingIsCanceled) { connectingIsCanceled = false; + cleanUpFunction.call(); } else { if (foundDevices.isEmpty()) { - stopServiceDiscovery(); cleanUpFunction.call(); } else { devicesFound.call(); } + stopServiceDiscovery(false); } } }, timeout); @@ -740,9 +768,12 @@ public void run() { private void discoverNetworkServices(final SalutCallback deviceNotSupported) { + foundDevices.clear(); + if(!receiverRegistered) { - dataReceiver.currentContext.registerReceiver(receiver, intentFilter); + Log.v(Salut.TAG, "Registered Salut reciever."); + dataReceiver.context.registerReceiver(receiver, intentFilter); receiverRegistered = true; } @@ -774,8 +805,8 @@ public void onFailure(int arg0) { if (arg0 == WifiP2pManager.P2P_UNSUPPORTED) deviceNotSupported.call(); if (arg0 == WifiP2pManager.NO_SERVICE_REQUESTS) { - disableWiFi(dataReceiver.currentContext); - enableWiFi(dataReceiver.currentContext); + disableWiFi(dataReceiver.context); + enableWiFi(dataReceiver.context); } } }); @@ -802,7 +833,7 @@ public void discoverNetworkServices(SalutCallback onDeviceFound, boolean callCon discoverNetworkServices(deviceNotSupported); } - public void discoverNetworkServicesWithTimeout(SalutCallback onDevicesFound, SalutCallback onDevicesNotFound, int timeout) + public void discoverWithTimeout(SalutCallback onDevicesFound, SalutCallback onDevicesNotFound, int timeout) { if(!respondersAlreadySet) { @@ -815,12 +846,11 @@ public void discoverNetworkServicesWithTimeout(SalutCallback onDevicesFound, Sal public void stopNetworkService(final boolean disableWiFi) { - if(isRunningAsHost) - { + if(isRunningAsHost) { Log.v(TAG, "Stopping network service..."); - stopServiceDiscovery(); - cleanUpDataConnection(false); - cleanUpDeviceConnection(false); + stopServiceDiscovery(true); + closeDataSocket(); + closeRegistrationSocket(); if (manager != null && channel != null && serviceInfo != null) { @@ -835,7 +865,7 @@ public void onSuccess() { Log.v(TAG, "Successfully shutdown service."); if(disableWiFi) { - disableWiFi(dataReceiver.currentContext); //Called here to give time for request to be disposed. + disableWiFi(dataReceiver.context); //Called here to give time for request to be disposed. } isRunningAsHost = false; } @@ -851,19 +881,18 @@ public void onSuccess() { } } - public void stopServiceDiscovery() + public void stopServiceDiscovery(boolean shouldUnregister) { if(isConnectedToAnotherDevice) disconnectFromDevice(); - if(receiverRegistered) + if(shouldUnregister) { - dataReceiver.currentContext.unregisterReceiver(receiver); + Log.v(Salut.TAG, "Unregistered Salut reciever."); + dataReceiver.context.unregisterReceiver(receiver); receiverRegistered = false; } - foundDevices.clear(); - if (manager != null && channel != null) { manager.removeServiceRequest(channel, serviceRequest, new WifiP2pManager.ActionListener() { @Override diff --git a/src/main/java/com/peak/salut/SalutBroadcastReciever.java b/src/main/java/com/peak/salut/SalutBroadcastReciever.java index f151f37..9cca4d4 100644 --- a/src/main/java/com/peak/salut/SalutBroadcastReciever.java +++ b/src/main/java/com/peak/salut/SalutBroadcastReciever.java @@ -9,9 +9,7 @@ import android.os.IBinder; import android.util.Log; -/** - * Created by markrjr on 2/4/15. - */ + public class SalutBroadcastReciever extends BroadcastReceiver { private WifiP2pManager manager; @@ -44,16 +42,27 @@ public void onReceive(Context context, Intent intent) { if (manager == null) { return; } + NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO); + if (networkInfo.isConnected() && networkInfo.getTypeName().equals("WIFI_P2P")) { - //Here, we are connected to another WiFi P2P device, and will automatically request connection info. + salutInstance.isConnectedToAnotherDevice = true; manager.requestConnectionInfo(channel, salutInstance); } else { - Log.v(TAG, "Not connected to another device."); salutInstance.isConnectedToAnotherDevice = false; + + Log.v(TAG, "Not connected to another device."); + if(salutInstance.thisDevice.isRegistered) + { + if(salutInstance.unexpectedDisconnect != null) + { + salutInstance.unregisterClient(salutInstance.unexpectedDisconnect, null, false); + } + } + } } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) { @@ -65,8 +74,6 @@ public void onReceive(Context context, Intent intent) { salutInstance.thisDevice.deviceName = device.deviceName; salutInstance.thisDevice.macAddress = device.deviceAddress; } - - //Log.v(TAG, device.deviceName + " is now using P2P. "); } } diff --git a/src/main/java/com/peak/salut/SalutDataReceiver.java b/src/main/java/com/peak/salut/SalutDataReceiver.java index 9d7544e..bab7add 100644 --- a/src/main/java/com/peak/salut/SalutDataReceiver.java +++ b/src/main/java/com/peak/salut/SalutDataReceiver.java @@ -1,6 +1,7 @@ package com.peak.salut; import android.app.Activity; +import android.content.Context; import com.peak.salut.Callbacks.SalutDataCallback; @@ -10,12 +11,14 @@ public class SalutDataReceiver { protected SalutDataCallback dataCallback; - protected Activity currentContext; + protected Context context; + protected Activity activity; public SalutDataReceiver(Activity activity, SalutDataCallback dataCallback) { this.dataCallback = dataCallback; - this.currentContext = activity; + this.context = activity.getApplicationContext(); + this.activity = activity; } }