tags:

views:

126

answers:

2

Hi All, I am writing an app that connects to a telnet server via wifi. I have a service that manages the socket connection. It all works fine, but when the phone sleeps it disconnects the wifi radio, which causes the socket connection to break (and throws a SocketException).

I feel like I should be able to set up a a broadcast receiver whose onResume() method is called when the wifi network connection is lost, and that would allow me to gracefully shut down the socket, and re-open it if the network is immediately re-connected. But I can't find anything like that in the doc or via searching.

Service code is here if you want it, thanks for the help, I really appreciate it!

    /**
 * 
 */
package com.wingedvictorydesign.LightfactoryRemote;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.text.Editable;
import android.util.Log;
import android.widget.Toast;
import android.os.Debug;

/**
 * @author Max
 *
 */
public class TelnetService extends Service {

 private final int DISCONNECTED = 0;
 private final int CONNECTED = 1;

    //place notifications in the notification bar
    NotificationManager mNM;

    protected InputStream in;
 protected OutputStream out;
 protected Socket socket;
 //the socket timeout, to prevent blocking if the server connection is lost.
 protected final int SO_TIMEOUT = 250;
 //holds the incoming stream from socket until it is ready to be read.
    BufferedReader inputBuffer;

    final RemoteCallbackList<TelnetServiceCallback> mCallbacks
     = new RemoteCallbackList<TelnetServiceCallback>();


    @Override
    public void onCreate() {
     super.onCreate();
     Log.d("LightfactoryRemote", "TelnetService onCreate()");
     mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
     }//end onCreate() 


    @Override
    public void onDestroy() {
     super.onDestroy();
     Log.d("LightfactoryRemote", "TelnetService onDestroy()");
     // Cancel the persistent notification, if it hasn't been already.
        mNM.cancel(R.string.telnet_service_connected);
     }//end onDestroy()

@Override
public IBinder onBind(Intent intent) {
 // TODO Auto-generated method stub
 Log.d("LightfactoryRemote", "TelnetService onBind()");
 return mBinder;
 }

@Override
public boolean onUnbind(Intent intent) {
    super.onUnbind(intent);
 Log.d("LightfactoryRemote", "TelnetService onUnBind()");
    return true;
}

@Override
public void onStart( Intent intent, int startId ) {
 super.onStart( intent, startId );
 Log.d("TelnetService", "TelnetService onStart()");
 }

private final TelnetServiceInterface.Stub mBinder = new TelnetServiceInterface.Stub() {
 public void registerCallback(TelnetServiceCallback cb) {
        if (cb != null) mCallbacks.register(cb);
    }
    public void unregisterCallback(TelnetServiceCallback cb) {
        if (cb != null) mCallbacks.unregister(cb);
    }



    public String connectToTelnet(String Host, int Port) throws RemoteException {

     //android.os.Debug.waitForDebugger();
     String hostInfo = null;
        try {
         socket = new java.net.Socket();
            socket.setSoTimeout(SO_TIMEOUT);
            socket.connect(new InetSocketAddress(Host, Port), 10000);  //setup the port with a timeout of 10sec.
            out = socket.getOutputStream();
            /*
             * in is wrapped in a reader, then in a Buffered reader.  This is supposedly better for performance,
             * and allows us to read a line at a time using the readLine() method.
             */
            inputBuffer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
      }
     catch(java.io.IOException e) {  
      Log.d("TelnetService.java", "Connection failed! " + e);
      /* if the connection fails, return null for serverResponse, which will
       * be handled appropriately on the client side.
       */
      return hostInfo;
      }

  //now that the command has been sent, read the response.
  hostInfo = readBuffer();
  Log.d("TelnetService.java", hostInfo);
  //notify the user that we are connected
  showNotification(CONNECTED, Host, Port);

  return hostInfo;
     }//end connectToTelnet

    /** Tests for a currently active connection.  Three cases must be distinguished.
  *  1. A connection attempt has not been made.  Return false.
  *  2. A connection attempt has been made, and socket is initialized, but no connection
  *   is active.  isConnected() returns false.
  *  3. A connection is active.  isConnected() returns true.
  */
    public boolean areYouThere() {
     if (socket != null) {
      boolean connectStatus = socket.isConnected();
      return connectStatus;
      }
     else {
      return false;
      }
     }//end areYouThere


    public void disconnect() {
     try {
      if (inputBuffer != null) {
       inputBuffer.close();
       }
      if (socket != null) {
       socket.close();
       }
      }
     catch (IOException e) {
   }
     // Cancel the persistent notification.
        mNM.cancel(R.string.telnet_service_connected);
     }//end disconnect()

    /** send the string to the telnet server, and return the response from server
  * If the connection is lost, an IOException results, so return null to be handled
  * appropriately on the client-side.
     * @throws RemoteException 
  */
 public String sendToTelnet(String toTelnet) throws RemoteException {
  if (out == null) {
   /*if out is still null, no connection has been made.  Throw
    * RemoteException to be handled on the client side.
    */   
   throw new RemoteException();
   }
  else {
   byte arr[];
   arr = (toTelnet + "\r" + "\n").getBytes();
   try {
    out.write(arr);
    //now that the command has been sent, read the response.
    String serverResponse = readBuffer();
    return serverResponse;
    }
   catch (IOException e) {
    /* if a connection was made, but then lost, we end up here.
     * throw a Remoteexception for handling by the client.
     */
    Log.d("TelnetService", "IO exception" + e);
    disconnect();
    throw new RemoteException();
    }
   }//end else
  }//end sendToTelnet

};//end ConnectService.Stub class   



public String readBuffer() {
 StringBuilder serverResponse = new StringBuilder();
 int character;
 try {
  //keep reading new lines into line until there are none left.
  while (inputBuffer.ready()) {
   /*as each character is read, append it to serverResponse,
    * throwing away the carriage returns (which read as glyphs),
    * and the ">" prompt symbols.
    */
   character = inputBuffer.read();
   if ((character != 13) && (character != 62)) {
    serverResponse.append( (char)character);
    }
   }
  }//end try
 catch (SocketTimeoutException e) {
  Log.d("TelnetService read()", "SocketTimeoutException");
  }
 catch (IOException e) {
  Log.d("TelnetService read()", "read() IO exception" + e);
  }

 return serverResponse.toString();
 }





/**
 * Show a notification while this service is running.
 */
private void showNotification(int event, String Host, int Port) {
 // In this sample, we'll use the same text for the ticker and the expanded notification
    CharSequence notificationText = "Connected to " + Host + " : " + Port;

 // Set the icon, scrolling text and timestamp
    Notification notification = new Notification(R.drawable.notbar_connected, notificationText,
            System.currentTimeMillis());
    //set the notification not to clear when the user hits "Clear All Notifications"
    notification.flags |= Notification.FLAG_NO_CLEAR; 
    // The PendingIntent to launch our activity if the user selects this notification
    PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
            new Intent(this, LightfactoryRemote.class), 0);

    // Set the info for the views that show in the notification panel.
    notification.setLatestEventInfo(this, getText(R.string.telnet_service_connected),
           notificationText, contentIntent);

    // Send the notification.
    // We use a string id because it is a unique number.  We use it later to cancel.
    mNM.notify(R.string.telnet_service_connected, notification);

 }//end showNotification()

} //end TelnetConnection
A: 

Not sure as to the exact way to do this but I think the ConnectivityManager would be a good place to start.

http://developer.android.com/reference/android/net/ConnectivityManager.html

you can get an instance of this class by calling Context.getSystemService(Context.CONNECTIVITY_SERVICE)

There are also some other good classes in android.net that you can use.

Hope that helps.

Mike
A: 

Register a BroadcastReceiver for ConnectivityManager.CONNECTIVITY_ACTION. In the onReceive handler you can call NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO) and then info.getType() and check for ConnectivityManager.TYPE_WIFI and do what you want then. :)

Qberticus