Android Open Source - wifikeyboard Http Server






From Project

Back to project page wifikeyboard.

License

The source code is released under:

GNU General Public License

If you think the Android project wifikeyboard listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/**
 * WiFi Keyboard - Remote Keyboard for Android.
 * Copyright (C) 2011 Ivan Volosyuk/* ww w.j a  v  a  2  s .  c om*/
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package com.volosyukivan;

import java.io.IOException;
import java.io.InvalidObjectException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;

import com.volosyukivan.HttpConnection.ConnectionFailureException;

import android.os.Handler;
import android.util.Log;


public abstract class HttpServer extends Thread {

  // private for network thread
  private Selector selector;
  private ServerSocketChannel ch;

  // FIXME: get rid of?
  private Handler handler;
  

  public HttpServer(ServerSocketChannel ch) {
    this.handler = new Handler();
    this.ch = ch;
    try {
      System.setProperty("java.net.preferIPv6Addresses", "false");
      selector = Selector.open();
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }
  
  abstract class Action {
    public abstract Object run();
  }
  
  private class ActionRunner implements Runnable {
    private Action action;
    private boolean finished; 
    private Object actionResult;
    
    private void setAction(Action action) {
      this.action = action;
      this.finished = false;
    }
    
    public void run() {
      actionResult = action.run();
      synchronized (this) {
        finished = true;
        notify();
      }
    }
    
    public synchronized Object waitResult() {
      while (!finished) {
        try {
          wait();
        } catch (InterruptedException e) {
          actionResult = null;
          return null;
        }
      }
      return actionResult;
    }
  };
  ActionRunner actionRunner = new ActionRunner();
  
  /**
   * Invoke from network thread and execute action on main thread (synchronized).
   * @param action to run on main thread
   * @return object return by the action
   */
  public Object runAction(Action action) {
    actionRunner.setAction(action);
    handler.post(actionRunner);
    return actionRunner.waitResult();
  }

  interface Update extends Runnable {}
  
  ArrayList<Update> pendingUpdates = new ArrayList<Update>();
  
  public void postUpdate(Update update) {
    pendingUpdates.add(update);
    try {
    selector.wakeup();
    } catch (Throwable t) {}
  }
  
  protected void setResponse(KeyboardHttpConnection con, ByteBuffer out) {
    try {
    con.key.interestOps(SelectionKey.OP_WRITE);
    con.outputBuffer = out;
    } catch (Exception e) {
      Log.e("wifikeyboard", "setResponse failed for hang connection", e);
    }
  }
  
  @Override
  public void run() {
//    Debug.d("HttpServer started listening");
    try {
      ch.configureBlocking(false);
      SelectionKey serverkey = ch.register(selector, SelectionKey.OP_ACCEPT);
      final ArrayList<Update> newUpdates = new ArrayList<Update>();
      Action checkUpdates = new Action() {
        @Override
        public Object run() {
          for (Update u : pendingUpdates) {
            newUpdates.add(u);
          }
          pendingUpdates.clear();
          return null;
        }
      };

      while (true) {
        newUpdates.clear();
        runAction(checkUpdates);
        for (Update u : newUpdates) {
          u.run();
        }
//        Debug.d("waiting for event");
        selector.select();
//        Debug.d("got an event");
        Set<SelectionKey> keys = selector.selectedKeys();

        for (Iterator<SelectionKey> i = keys.iterator(); i.hasNext();) {
          SelectionKey key = i.next();
          i.remove();

          if (key == serverkey) {
            if (key.isAcceptable()) {
              SocketChannel client = ch.accept();
//              Debug.d("NEW CONNECTION from " + client.socket().getRemoteSocketAddress());
              client.configureBlocking(false);
              SelectionKey clientkey = client.register(selector, SelectionKey.OP_READ);
              HttpConnection con = newConnection(client);
              clientkey.attach(con);
              con.setKey(clientkey);
              
            }
          } else {
            HttpConnection conn = (HttpConnection) key.attachment();
            try {
              HttpConnection.ConnectionState prevState, newState;
              if (key.isReadable()) {
                prevState = HttpConnection.ConnectionState.SELECTOR_WAIT_FOR_NEW_INPUT; 
//                Debug.d("processing read event");
//                long start = System.currentTimeMillis();
                newState = conn.newInput();
//                long end = System.currentTimeMillis();
//                Debug.d("delay = " + (end - start));

//                int size = android.os.Debug.getThreadAllocSize();
//                android.os.Debug.stopAllocCounting();
//                Log.d("wifikeyboard", "finished read event, allocs = " + size);
//                android.os.Debug.startAllocCounting();

              } else if (key.isWritable()) {
                prevState = HttpConnection.ConnectionState.SELECTOR_WAIT_FOR_OUTPUT_BUFFER; 
//                Debug.d("processing write event");
                newState = conn.newOutputBuffer();
//                Log.d("wifikeyboard", "finished write event");
              } else {
                continue;
              }
              if (newState == prevState) continue;
              key.interestOps(
                  (newState == HttpConnection.ConnectionState.SELECTOR_WAIT_FOR_NEW_INPUT ? SelectionKey.OP_READ : 0) |
                  (newState == HttpConnection.ConnectionState.SELECTOR_WAIT_FOR_OUTPUT_BUFFER ? SelectionKey.OP_WRITE : 0));
            } catch (IOException io) {
//              Debug.d("CONNECTION CLOSED from " + 
//                  conn.getClient().socket().getRemoteSocketAddress());
              if (key != null) key.cancel();
              conn.getClient().close();
            } catch (ConnectionFailureException e) {
              if (key != null) key.cancel();
              conn.getClient().close();
            } catch (NumberFormatException e) {
              // FIXME: move to ConnectionFailureException
              if (key != null) key.cancel();
              conn.getClient().close();
            }
          }
        }
      }
        
    } catch (IOException e) {
      Debug.e("network loop terminated", e);
    } catch (NetworkThreadStopException e) {
      Debug.e("network thread stop requested", e);
    }
    try {
      selector.close();
    } catch (Throwable t) {}
    try {
      ch.close();
    } catch (Throwable t) {}
    onExit();
  }
  
  class NetworkThreadStopException extends RuntimeException {
    private static final long serialVersionUID = 1L;
    public NetworkThreadStopException(String msg) {
      super(msg);
    }
  }
  
  public synchronized void finish() {
    postUpdate(new Update() {
      @Override
      public void run() {
        throw new NetworkThreadStopException("network thread stop requested");
      }
    });
  }
  
  public abstract HttpConnection newConnection(SocketChannel ch);
  /**
   * Called on the end of network thread.
   */
  protected abstract void onExit();
}




Java Source Code List

com.volosyukivan.Debug.java
com.volosyukivan.HttpConnection.java
com.volosyukivan.HttpServer.java
com.volosyukivan.HttpService.java
com.volosyukivan.KeyboardHttpConnection.java
com.volosyukivan.KeyboardHttpServer.java
com.volosyukivan.KeycodeConvertor.java
com.volosyukivan.WiFiInputMethod.java
com.volosyukivan.WiFiKeyboard.java
com.volosyukivan.WidgetActivity.java
com.volosyukivan.WidgetConfigure.java
com.volosyukivan.WidgetProvider.java