Skip to content

Commit f59cbc8

Browse files
author
davidgraeff
committed
Version 1.9c
* Fix crashes caused by PluginController * Only load PluginController if enabled * PluginController works reliable now * Support unloaded/vanished plugins * Do not restore Activity with Feedback Dialog * Fix problem with InetAddress.getByName in gui thread * Send broadcast packets to all network interfaces * Show better error messages if network is not reachable * Query existing devices only, if network does not support broadcasts (2G, 3G)
1 parent ad89ae2 commit f59cbc8

File tree

16 files changed

+477
-436
lines changed

16 files changed

+477
-436
lines changed

.idea/workspace.xml

Lines changed: 182 additions & 241 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/src/main/AndroidManifest.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
33
package="oly.netpowerctrl"
4-
android:versionCode="16"
5-
android:versionName="1.9b">
4+
android:versionCode="17"
5+
android:versionName="1.9c">
66

77
<!-- Api level 14: Android 4.0 15. Dezember 2011 -->
88
<!-- Api level 16: Android 4.1 27. Juni 2012 -->

app/src/main/aidl/oly/netpowerctrl/plugins/INetPwrCtrlPlugin.aidl

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ package oly.netpowerctrl.plugins;
33
import oly.netpowerctrl.plugins.INetPwrCtrlPluginResult;
44

55
interface INetPwrCtrlPlugin {
6-
void requestValues(INetPwrCtrlPluginResult cb);
7-
void updateIntValue(int id, int value, INetPwrCtrlPluginResult cb);
8-
void updateBooleanValue(int id, boolean value, INetPwrCtrlPluginResult cb);
9-
void executeAction(int id, INetPwrCtrlPluginResult cb);
6+
void init(INetPwrCtrlPluginResult cb);
7+
void requestValues();
8+
void updateIntValue(int id, int value);
9+
void updateBooleanValue(int id, boolean value);
10+
void executeAction(int id);
1011
}

app/src/main/aidl/oly/netpowerctrl/plugins/INetPwrCtrlPluginResult.aidl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package oly.netpowerctrl.plugins;
22

33
interface INetPwrCtrlPluginResult {
4+
void ready();
45
void intValue(int id, String name, int min, int max, int value);
56
void booleanValue(int id, String name, boolean value);
67
void action(int id, String name);

app/src/main/java/oly/netpowerctrl/anelservice/DeviceQuery.java

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import java.util.Collection;
88
import java.util.Iterator;
99

10-
import oly.netpowerctrl.datastructure.DeviceCommand;
1110
import oly.netpowerctrl.datastructure.DeviceInfo;
1211
import oly.netpowerctrl.main.NetpowerctrlApplication;
1312

@@ -39,9 +38,7 @@ public DeviceQuery(Context context, DeviceUpdateStateOrTimeout target, DeviceInf
3938
// Register on main application object to receive device updates
4039
NetpowerctrlApplication.instance.addUpdateDeviceState(this);
4140

42-
43-
// Send out broadcast
44-
if (!DeviceSend.instance().sendQuery(context, device_to_observe.HostName, device_to_observe.SendPort, rangeCheck)) {
41+
if (!DeviceSend.instance().sendQuery(device_to_observe.HostName, device_to_observe.SendPort, rangeCheck)) {
4542
// Device not in range, immediately timeout
4643
timeoutHandler.postDelayed(timeoutRunnable, 0);
4744
} else
@@ -60,10 +57,10 @@ public DeviceQuery(Context context, DeviceUpdateStateOrTimeout target,
6057

6158
// Send out broadcast
6259
if (queryForNewDevices)
63-
sendBroadcastQuery(context);
60+
DeviceSend.instance().sendBroadcastQuery();
6461
else
6562
for (DeviceInfo di : devices_to_observe)
66-
DeviceSend.instance().sendQuery(context, di.HostName, di.SendPort, rangeCheck);
63+
DeviceSend.instance().sendQuery(di.HostName, di.SendPort, rangeCheck);
6764
}
6865

6966
/**
@@ -88,20 +85,4 @@ public boolean notifyObservers(DeviceInfo received_data) {
8885
}
8986
return false;
9087
}
91-
92-
/**
93-
* Used to be used only from the DeviceSend class for requesting an update
94-
* after a command has been send
95-
*
96-
* @param context Context
97-
* @param device_command A DeviceCommand object containing destination IP, Port and commands
98-
*/
99-
static void sendQuery(final Context context, DeviceCommand device_command) {
100-
DeviceSend.instance().sendQuery(context, device_command.dest.getHostAddress(), device_command.port, false);
101-
}
102-
103-
private static void sendBroadcastQuery(final Context context) {
104-
for (int port : NetpowerctrlApplication.instance.getAllSendPorts())
105-
DeviceSend.instance().sendQuery(context, "255.255.255.255", port, false);
106-
}
10788
}

app/src/main/java/oly/netpowerctrl/anelservice/DeviceSend.java

Lines changed: 123 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package oly.netpowerctrl.anelservice;
22

33
import android.content.Context;
4+
import android.util.Log;
5+
import android.widget.Toast;
46

57
import java.net.DatagramPacket;
68
import java.net.DatagramSocket;
@@ -9,14 +11,17 @@
911
import java.net.NetworkInterface;
1012
import java.net.SocketException;
1113
import java.net.UnknownHostException;
12-
import java.nio.ByteBuffer;
14+
import java.util.ArrayList;
1315
import java.util.Collection;
1416
import java.util.Enumeration;
17+
import java.util.Iterator;
1518
import java.util.Locale;
19+
import java.util.Set;
1620
import java.util.concurrent.LinkedBlockingQueue;
1721

1822
import oly.netpowerctrl.R;
1923
import oly.netpowerctrl.datastructure.DeviceCommand;
24+
import oly.netpowerctrl.datastructure.DeviceInfo;
2025
import oly.netpowerctrl.datastructure.OutletInfo;
2126
import oly.netpowerctrl.main.NetpowerctrlApplication;
2227
import oly.netpowerctrl.utils.ShowToast;
@@ -27,6 +32,9 @@
2732
*/
2833
public class DeviceSend {
2934
private static final int INQUERY_REQUEST = 0;
35+
private static final int INQUERY_BROADCAST_REQUEST = 1;
36+
private static final int NETWORK_UNREACHABLE = 2;
37+
3038
// Singleton
3139
static DeviceSend mInstance = new DeviceSend();
3240

@@ -45,7 +53,7 @@ public void interrupt() {
4553
public void addSendJob(String hostname, int port, byte[] message, boolean broadcast, int errorID) throws UnknownHostException {
4654
if (!sendThread.isAlive())
4755
sendThread.start();
48-
q.add(new SendJob(InetAddress.getByName(hostname), port, message, broadcast, errorID));
56+
q.add(new SendJob(hostname, port, message, broadcast, errorID));
4957
}
5058

5159
public void addSendJob(InetAddress ip, int port, byte[] message, boolean broadcast, int errorID) {
@@ -111,7 +119,8 @@ void process() {
111119
}
112120

113121
class SendJob extends Job {
114-
InetAddress ip;
122+
InetAddress ip = null;
123+
String hostname;
115124
int port;
116125
byte[] message;
117126
boolean broadcast;
@@ -125,23 +134,51 @@ class SendJob extends Job {
125134
this.errorID = errorID;
126135
}
127136

137+
SendJob(String hostname, int port, byte[] message, boolean broadcast, int errorID) {
138+
this.hostname = hostname;
139+
this.message = message;
140+
this.port = port;
141+
this.broadcast = broadcast;
142+
this.errorID = errorID;
143+
}
144+
128145
@Override
129146
void process() {
130147
try {
148+
if (hostname != null && hostname.length() > 0) {
149+
ip = InetAddress.getByName(hostname);
150+
hostname = "";
151+
}
131152
datagramSocket.setBroadcast(broadcast);
132153
datagramSocket.send(new DatagramPacket(message, message.length, ip, port));
154+
} catch (final SocketException e) {
155+
if (e.getMessage().contains("ENETUNREACH"))
156+
onError(NETWORK_UNREACHABLE, ip, port, e);
157+
else {
158+
e.printStackTrace();
159+
onError(errorID, ip, port, e);
160+
}
133161
} catch (final Exception e) {
134-
onError(errorID, e);
162+
e.printStackTrace();
163+
onError(errorID, ip, port, e);
135164
}
136165
}
137166
}
138167

139-
private void onError(int errorID, Exception e) {
168+
private void onError(int errorID, InetAddress ip, int port, Exception e) {
140169
Context context = NetpowerctrlApplication.instance;
141170
switch (errorID) {
142171
case INQUERY_REQUEST:
143172
ShowToast.FromOtherThread(context,
144-
context.getResources().getString(R.string.error_sending_inquiry) + ": " + e.getMessage());
173+
context.getResources().getString(R.string.error_sending_inquiry, ip.getHostAddress()) + ": " + e.getMessage());
174+
break;
175+
case INQUERY_BROADCAST_REQUEST:
176+
ShowToast.FromOtherThread(context,
177+
context.getResources().getString(R.string.error_sending_broadcast_inquiry, port) + ": " + e.getMessage());
178+
break;
179+
case NETWORK_UNREACHABLE:
180+
ShowToast.FromOtherThread(context,
181+
context.getResources().getString(R.string.error_not_in_range, ip.getHostAddress()));
145182
break;
146183
}
147184
}
@@ -155,18 +192,65 @@ private byte[] generateAllOutletsDatagramBytes(final DeviceCommand device) {
155192
return data;
156193
}
157194

158-
boolean sendQuery(final Context context, final String hostname, final int port, boolean rangeCheck) {
159-
if (rangeCheck) {
160-
try {
161-
if (!isIPinNetworkAddressPool(InetAddress.getByName(hostname))) {
162-
ShowToast.FromOtherThread(context, context.getResources().getString(R.string.error_not_in_range) + ": " + hostname);
163-
return false;
195+
void sendBroadcastQuery() {
196+
Set<Integer> ports = NetpowerctrlApplication.instance.getAllSendPorts();
197+
boolean foundBroadcastAddresses = false;
198+
199+
Enumeration list;
200+
try {
201+
list = NetworkInterface.getNetworkInterfaces();
202+
203+
while (list.hasMoreElements()) {
204+
NetworkInterface iface = (NetworkInterface) list.nextElement();
205+
206+
if (iface == null) continue;
207+
208+
if (!iface.isLoopback() && iface.isUp()) {
209+
210+
Iterator it = iface.getInterfaceAddresses().iterator();
211+
while (it.hasNext()) {
212+
InterfaceAddress address = (InterfaceAddress) it.next();
213+
//System.out.println("Found address: " + address);
214+
if (address == null) continue;
215+
InetAddress broadcast = address.getBroadcast();
216+
if (broadcast == null) continue;
217+
for (int port : ports)
218+
addSendJob(broadcast, port, "wer da?\r\n".getBytes(), true, INQUERY_BROADCAST_REQUEST);
219+
foundBroadcastAddresses = true;
220+
}
164221
}
165-
} catch (final Exception e) {
166-
ShowToast.FromOtherThread(context, context.getResources().getString(R.string.error_not_in_range) + ": " + hostname);
167-
return false;
222+
}
223+
} catch (SocketException ex) {
224+
Log.w("sendBroadcastQuery", "Error while getting network interfaces");
225+
ex.printStackTrace();
226+
}
227+
228+
if (!foundBroadcastAddresses) {
229+
// Broadcast not allowed on this network. Show hint to user
230+
Toast.makeText(NetpowerctrlApplication.instance,
231+
NetpowerctrlApplication.instance.getString(R.string.devices_no_new_on_network),
232+
Toast.LENGTH_SHORT).show();
233+
234+
// Query all existing devices directly
235+
ArrayList<DeviceInfo> devices = NetpowerctrlApplication.instance.configuredDevices;
236+
for (DeviceInfo di : devices) {
237+
sendQuery(di.HostName, di.SendPort, false);
168238
}
169239
}
240+
}
241+
242+
boolean sendQuery(final String hostname, final int port, boolean rangeCheck) {
243+
if (rangeCheck) {
244+
// try {
245+
// if (!isIPinNetworkAddressPool(InetAddress.getByName(hostname))) {
246+
// ShowToast.FromOtherThread(context, context.getResources().getString(R.string.error_not_in_range) + ": " + hostname);
247+
// return false;
248+
// }
249+
// } catch (final SocketException e) {
250+
// ShowToast.FromOtherThread(context, context.getResources().getString(R.string.error_not_in_range) + ": " + hostname+" "+e.getMessage());
251+
// return false;
252+
// }
253+
}
170254
try {
171255
addSendJob(hostname, port, "wer da?\r\n".getBytes(), true, INQUERY_REQUEST);
172256
} catch (UnknownHostException e) {
@@ -218,28 +302,28 @@ public void sendOutlets(final Collection<DeviceCommand> device_commands, final b
218302
}
219303
}
220304
}
221-
222-
static private boolean isIPinNetworkAddressPool(InetAddress ip) throws SocketException {
223-
byte[] ipAddressBytes = ip.getAddress();
224-
// Iterate all NICs (network interface cards)...
225-
for (Enumeration networkInterfaceEnumerator = NetworkInterface.getNetworkInterfaces(); networkInterfaceEnumerator.hasMoreElements(); ) {
226-
NetworkInterface networkInterface = (NetworkInterface) networkInterfaceEnumerator.nextElement();
227-
for (InterfaceAddress interfaceAddress : networkInterface.getInterfaceAddresses()) {
228-
InetAddress interfaceIPAddress = interfaceAddress.getAddress();
229-
byte[] interfaceIPBytes = interfaceIPAddress.getAddress();
230-
if (ipAddressBytes.length != interfaceIPBytes.length)
231-
continue; // different ip versions
232-
233-
byte[] subNetMaskBytes = ByteBuffer.allocate(4).putInt(interfaceAddress.getNetworkPrefixLength()).array();
234-
// check each byte of both addresses while applying the subNet mask
235-
for (int i = 0; i < interfaceIPBytes.length; ++i) {
236-
if ((ipAddressBytes[i] & subNetMaskBytes[i]) !=
237-
(interfaceIPBytes[i] & subNetMaskBytes[i]))
238-
continue; // byte not identical, the ip is not for this network interface
239-
}
240-
return true;
241-
}
242-
}
243-
return false;
244-
}
305+
//
306+
// static private boolean isIPinNetworkAddressPool(InetAddress ip) throws SocketException {
307+
// byte[] ipAddressBytes = ip.getAddress();
308+
// // Iterate all NICs (network interface cards)...
309+
// for (Enumeration networkInterfaceEnumerator = NetworkInterface.getNetworkInterfaces(); networkInterfaceEnumerator.hasMoreElements(); ) {
310+
// NetworkInterface networkInterface = (NetworkInterface) networkInterfaceEnumerator.nextElement();
311+
// for (InterfaceAddress interfaceAddress : networkInterface.getInterfaceAddresses()) {
312+
// InetAddress interfaceIPAddress = interfaceAddress.getAddress();
313+
// byte[] interfaceIPBytes = interfaceIPAddress.getAddress();
314+
// if (ipAddressBytes.length != interfaceIPBytes.length)
315+
// continue; // different ip versions
316+
//
317+
// byte[] subNetMaskBytes = ByteBuffer.allocate(4).putInt(interfaceAddress.getNetworkPrefixLength()).array();
318+
// // check each byte of both addresses while applying the subNet mask
319+
// for (int i = 0; i < interfaceIPBytes.length; ++i) {
320+
// if ((ipAddressBytes[i] & subNetMaskBytes[i]) !=
321+
// (interfaceIPBytes[i] & subNetMaskBytes[i]))
322+
// continue; // byte not identical, the ip is not for this network interface
323+
// }
324+
// return true;
325+
// }
326+
// }
327+
// return false;
328+
// }
245329
}

0 commit comments

Comments
 (0)