I am writing a chat program for android os 2.3 and above. I have been following some examples and got it working perfectly with all my extra bells and whistles on OS 2.3.x.
My problem comes with OS > 2.3.x ie honeycomb and specifically ICS (I have an ICS device for testing).
I am unable to send (packet). It crashes with an error every time. The answer indicated on here seems to be to run the thread inside a service.
Unfortunately that has always been the case - I want to open extra windows and keep a service grabbing data before passing it back to the main activity, regardless of the fact that the main window may open another window - when you go back the entire chat history , including everything you missed.
Can anyone point me to what I need to do to get this to NOT release an error everytime the code hits the send (packet) in OS 4.0 (ICS)?
Thanks in advance. Full Source of the service is here.
package com.rpg.phg.themesh;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.DhcpInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
/**
* This class does all the work for sending and receiving broadcast packets.
* It has a thread that listens for incoming packets.
*/
public class TheMesh_ChatService extends Service
{
// Debugging
private static final String TAG = "TheMesh_ChatService";
private static final boolean D = true;
private static String myIP = null;
// Member fields
private final Handler mHandler;
private ComService mConnectedService;
Context mContext ;
/**
* Constructor. Prepares a new Broadcast service.
* @param context The UI Activity Context
* @param handler A Handler to send messages back to the UI Activity
*/
public TheMesh_ChatService(Context context, Handler handler, String ourIP) {
//mAdapter = BluetoothAdapter.getDefaultAdapter();
mContext = context;
mHandler = handler;
myIP = ourIP;
}
/**
* Start the chat service. Specifically start ComThread to begin
* listening incoming broadcast packets.
*/
public synchronized void start() {
if (D) Log.d(TAG, "Started Service");
mConnectedService = new ComService();
mConnectedService.start();
}
/**
* Stop thread
*/
public synchronized void stop() {
if (D) Log.d(TAG, "stop");
if (mConnectedService != null) {mConnectedService.cancel(); mConnectedService = null;}
}
public void write(byte[] out, String IP) {
mConnectedService.write(out, IP);
}
/**
* This thread handles all incoming and outgoing transmissions.
*
* This actually needs to be turned onto the TheMesh_ChatService
*/
private class ComService extends Thread {
// Should we create a Thread here?
// It *should* stay running until the service ends...
private static final int BCAST_PORT = 2568;
DatagramSocket mSocket ;
InetAddress myBcastIP, myLocalIP, myRemoteIP = null ;
public ComService() {
try {
myBcastIP = getBroadcastAddress();
if(D)Log.d(TAG,"my bcast ip : "+myBcastIP);
//myLocalIP = getLocalAddress();
myLocalIP = InetAddress.getByName(myIP);
if(D)Log.d(TAG,"my local ip : "+myLocalIP);
mSocket = new DatagramSocket(BCAST_PORT);
mSocket.setBroadcast(true);
} catch (IOException e) {
Log.e(TAG, "Could not make socket", e);
}
}
public void run() {
try {
byte[] buf = new byte[1024];
//Listen on socket to receive messages
while (true) {
DatagramPacket packet = new DatagramPacket(buf, buf.length);
mSocket.receive(packet);
InetAddress remoteIP = packet.getAddress();
if(remoteIP.equals(myLocalIP))
continue;
String s = new String(packet.getData(), 0, packet.getLength());
if(D)Log.d(TAG, "Received response " + s);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(TheMesh_PAN.MESSAGE_READ,-1,-1, s)
.sendToTarget();
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Write broadcast packet.
*/
public void write(byte[] buffer, String IP) {
try {
String data = new String (buffer);
if (IP.equalsIgnoreCase("ALL"))
{
DatagramPacket packet = new DatagramPacket(data.getBytes(), data.length(),
myBcastIP, BCAST_PORT);
mSocket.send(packet); // logcat shows crash here!
} else
{
myRemoteIP = InetAddress.getByName(IP); // Will this generate Exceptions if lookup fails?
DatagramPacket packet = new DatagramPacket(data.getBytes(), data.length(),
myRemoteIP, BCAST_PORT);
mSocket.send(packet); // and logcat shows crash here.
}
// Share the sent message back to the UI Activity
mHandler.obtainMessage(TheMesh_PAN.MESSAGE_WRITE, -1, -1, data)
.sendToTarget();
} catch (Exception e) {
Log.e(TAG, "Exception during write", e);
}
}
/**
* Calculate the broadcast IP we need to send the packet along.
*/
private InetAddress getBroadcastAddress() throws IOException {
WifiManager mWifi = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
WifiInfo info = mWifi.getConnectionInfo();
if(D)Log.d(TAG,"\n\nWiFi Status: " + info.toString());
// DhcpInfo is a simple object for retrieving the results of a DHCP request
DhcpInfo dhcp = mWifi.getDhcpInfo();
if (dhcp == null) {
Log.d(TAG, "Could not get dhcp info");
return null;
}
int broadcast = (dhcp.ipAddress & dhcp.netmask) | ~dhcp.netmask;
byte[] quads = new byte[4];
for (int k = 0; k < 4; k++)
quads[k] = (byte) ((broadcast >> k * 8) & 0xFF);
return InetAddress.getByAddress(quads); // The high order byte is quads[0].
}
public void cancel() {
try {
mSocket.close();
} catch (Exception e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
}
This all works as is. Most of the program is taken from "broadcastchat4" (sorry I forget which website I got it from). Ive added to it, especially the calling program.
As soon as the send is called from inside the write function (which is called whilst the run() is running as it monitors incoming traffic whilst the write handles outgoing traffic), I get the following in logcat:
09-22 19:32:24.959: E/TheMesh_ChatService(17320): Exception during write
09-22 19:32:24.959: E/TheMesh_ChatService(17320): android.os.NetworkOnMainThreadException
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1099)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at libcore.io.BlockGuardOs.sendto(BlockGuardOs.java:175)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at libcore.io.IoBridge.sendto(IoBridge.java:463)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at java.net.PlainDatagramSocketImpl.send(PlainDatagramSocketImpl.java:182)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at java.net.DatagramSocket.send(DatagramSocket.java:287)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at com.rpg.phg.themesh.TheMesh_ChatService$ComService.write(TheMesh_ChatService.java:146)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at com.rpg.phg.themesh.TheMesh_ChatService.write(TheMesh_ChatService.java:69)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at com.rpg.phg.themesh.TheMesh_PAN.sendMessage(TheMesh_PAN.java:513)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at com.rpg.phg.themesh.TheMesh_PAN.access$11(TheMesh_PAN.java:494)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at com.rpg.phg.themesh.TheMesh_PAN$3.onKey(TheMesh_PAN.java:264)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at android.view.View.dispatchKeyEvent(View.java:5495)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1246)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1246)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1246)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1246)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1246)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1246)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchKeyEvent(PhoneWindow.java:1879)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1361)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at android.app.Activity.dispatchKeyEvent(Activity.java:2324)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1806)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at android.view.ViewRootImpl.deliverKeyEventPostIme(ViewRootImpl.java:3327)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2597)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at android.os.Handler.dispatchMessage(Handler.java:99)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at android.os.Looper.loop(Looper.java:137)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at android.app.ActivityThread.main(ActivityThread.java:4424)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at java.lang.reflect.Method.invokeNative(Native Method)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at java.lang.reflect.Method.invoke(Method.java:511)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
09-22 19:32:24.959: E/TheMesh_ChatService(17320): at dalvik.system.NativeStart.main(Native Method)
Any ideas as to how to make this ICS (actually I suspect it wont work on honeycomb or higher since the network changes seem to have been incorporated in v3+) work?