MonomeView.java :  » UnTagged » androidome » uk » co » ewanhemingway » androidome » Android Open Source

Android Open Source » UnTagged » androidome 
androidome » uk » co » ewanhemingway » androidome » MonomeView.java
package uk.co.ewanhemingway.androidome;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.channels.DatagramChannel;
import java.util.ArrayList;
import java.util.Iterator;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Paint.Style;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import com.illposed.osc.OSCPortOut;
import com.illposed.osc.OSCMessageOut;

import de.sciss.net.OSCListener;
import de.sciss.net.OSCMessage;
import de.sciss.net.OSCReceiver;

public class MonomeView extends View{

  // OSC objects
  private OSCReceiver rcv;
  private OSCPortOut oscPortOut;
  DatagramChannel dch;
  SocketAddress outgoingAddr;

  int cellSize = 56;
  String prefix = " ";
  String deviceIPAddress = " ";
  String hostIPAddress = "192.168.1.164";
  boolean sendingTiltOSC = false;

  Boolean[][] gridLit;

  private long _moveDelay = 50;

  private int runMode = 0;
  public static final int PAUSE = 0;
  public static final int RUNNING = 1;
  public static final int GRID_WIDTH = 8;
  public static final int GRID_HEIGHT = 8;

  ArrayList<TouchStream> list = new ArrayList<TouchStream>();

  // animation stuff
  private RefreshHandler _redrawHandler = new RefreshHandler();
  class RefreshHandler extends Handler {

    @Override
    public void handleMessage(Message message) {
      MonomeView.this.update();
      MonomeView.this.invalidate();
    }

    public void sleep(long delayMillis) {
      removeMessages(0);
      sendMessageDelayed(obtainMessage(0), delayMillis);
    }
  };

  private void update() {
    if(runMode == RUNNING) _redrawHandler.sleep(_moveDelay);
  }

  public MonomeView(Context context, AttributeSet attrs) {
    super(context, attrs);
    initialiseMonomeGrid();
  }

  // clear grid
  public void initialiseMonomeGrid(){
    // start animation thread
    runMode = RUNNING;
    update();

    // initialise grid to store LED status
    gridLit = new Boolean[8][8];
    // and clear it 
    resetGrid(false);
  }
  
  // set up OSC listeners etc
  public void initialiseIncomingOSC(){

    rcv = null;
    dch = null;
    
    try {
      final SocketAddress incomingPort = new InetSocketAddress(8080);

      dch = DatagramChannel.open();
      dch.socket().bind(incomingPort);    // assigns a local socket address to the listener
      rcv = OSCReceiver.newUsing(dch);

      rcv.addOSCListener( new OSCListener() {
        public void messageReceived( OSCMessage message, SocketAddress sender, long time ){

          String address = message.getName().trim();
          int numArgs = message.getArgCount();

          // avoid String null pointer
          if(address.length() <= prefix.length()) return;
          
          // if the incoming messages are addressed to us,
          // i.e incoming prefix matches the stored prefix 
          if(address.substring(1, prefix.length()+1).equalsIgnoreCase(prefix)){
            address = address.substring(prefix.length()+2);

            // most likely message is led calls 
            // NOTE: must check that we have 3 arguments (x, y, on/off)
            if(address.equalsIgnoreCase("led") && numArgs == 3){

              int xPos = ((Number) message.getArg( 0 )).intValue();
              int yPos = ((Number) message.getArg( 1 )).intValue();
              int value = ((Number) message.getArg( 2 )).intValue();

              setLED(xPos, yPos, value);
            }
            // check for message to light up a column
            else if(address.equalsIgnoreCase("led_col") && numArgs == 2){

              int col = ((Number) message.getArg( 0 )).intValue();
              int value = ((Number) message.getArg( 1 )).intValue();

              setLEDCol(col, value);
            } 
            // check for message to light up a row
            else if(address.equalsIgnoreCase("led_row") && numArgs == 2){
              int row = ((Number) message.getArg( 0 )).intValue();
              int value = ((Number) message.getArg( 1 )).intValue();

              setLEDRow(row, value);
            } 
            // check for message to clear the board
            else if(address.equalsIgnoreCase("clear") && numArgs == 1){

              boolean flag = message.getArg(0).toString().equalsIgnoreCase("1");
              resetGrid(flag);
            } // check for message to turn on tilt reporting
            // should be off by default
            else if(address.equalsIgnoreCase("tiltmode") && numArgs == 1){
              boolean flag = message.getArg(0).toString().equalsIgnoreCase("1");
              setTiltMode(flag);
            }
          }

        }
      });
      rcv.startListening();

    }
    catch( IOException e2 ) {
      e2.printStackTrace();
    }

  }



  private void setLEDCol(int col, int value) {
    int check = 1;
    for(int i = 0; i < GRID_HEIGHT; i++){
      try{
        gridLit[col][i] = ((value & check) != 0);
      }catch(ArrayIndexOutOfBoundsException e){
        e.printStackTrace();
      }
      check = check << 1;  
    }
  }

  private void setLEDRow(int row, int value) {
    int check = 1;
    for(int i = 0; i < GRID_HEIGHT; i++){
      try{
        gridLit[i][row] = ((value & check) != 0);
      }catch(ArrayIndexOutOfBoundsException e){
        e.printStackTrace();
      }
      check = check << 1;  
    }
  }

  // resets the whole grid
  // code: true on, false off
  public void resetGrid(boolean gridOn){
    for(int i = 0; i < 8; i++)
      for(int j = 0; j < 8; j++)
        gridLit[i][j] = gridOn;
  }

  // to be tided up
  public void setLED(int xPos, int yPos, int state){

    // ignore input outside 8x8 grid 
    if(xPos < 0 || xPos >= GRID_WIDTH || yPos < 0 || yPos >= GRID_HEIGHT) return;
    gridLit[xPos][yPos] = (state == 1) ? true : false;
  }

  // set OSC prefix and update listener filters
  public void setPrefix(String prefix){
    this.prefix = prefix;
  }

  // create a method for the addressChanged action
  public void pingMaxWithSetupData() {
    // the variable OSCPortOut tries to get an instance of OSCPortOut at the address
    try {
      oscPortOut = new OSCPortOut(InetAddress.getByName(hostIPAddress));   
      // if the oscPort variable fails to be instantiated then sent the error message
    } catch (Exception e) {
      Log.e("Connection Error", "Couldn't set address" + e);
    }

    Object[] oscArgs = {deviceIPAddress};
    OSCMessageOut oscMsgIP = new OSCMessageOut("/androidome/setup", oscArgs);
    OSCMessageOut oscMsgPrefix = new OSCMessageOut("/sys/prefix /" + prefix, null);

    sendOSCMessage(oscMsgIP);
    sendOSCMessage(oscMsgPrefix);
  }

  // stop listeners/animation  when app looses focus
  public void pauseMonomeGrid(){

    // close up the listeners
    if(rcv != null){
      rcv.dispose();
    }else if(dch != null){
      try {
        dch.close();
      }catch( IOException e4 ) {
        e4.printStackTrace();
      }
    }

    oscPortOut.close();

    // pause the animation thread
    runMode = PAUSE;
  }

  // paint the grid etc
  protected void onDraw(Canvas canvas) {
    Paint background = new Paint();
    background.setColor(getResources().getColor(R.color.background));

    Paint cell = new Paint();
    cell.setColor(getResources().getColor(R.color.button));

    // draw background
    canvas.drawRect(0, 0, getWidth(), getHeight(), background);

    // draw cells
    for (int h = 0; h < 8; h++) {
      for (int w = 0; w < 8; w++) {

        if(gridLit[w][h]){
          cell.setColor(getResources().getColor(R.color.lit));
          cell.setStyle(Style.FILL);
        }else {
          cell.setColor(getResources().getColor(R.color.button));
          cell.setStyle(Style.STROKE);
        }

        RectF bounds = new RectF(w * cellSize, h* cellSize, (w * cellSize) + (cellSize - 5), (h * cellSize) + (cellSize - 5));
        canvas.drawRoundRect(bounds, 4, 4, cell);
      }
    }
  }

  // Handles multitouch input, dragging etc
  @Override 
  public boolean onTouchEvent(MotionEvent ev) { 

    final int action = ev.getAction();

    switch (action & MotionEvent.ACTION_MASK) {

    case MotionEvent.ACTION_DOWN: {

      // find which cell the initial touch took place in
      int x = (int)ev.getX()/cellSize;
      int y = (int)ev.getY()/cellSize;

      // exclude touches outside the grid
      if(x < 0 || x >= GRID_WIDTH || y < 0 || y >= GRID_HEIGHT) return true;

      sendTouchOSC(x, y, 1);
      final int pointerIndex = (action & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;

      TouchStream first = new TouchStream(x, y, pointerIndex);

      // Save the ID of this pointer 
      list.add(first);
      break;
    }
    case MotionEvent.ACTION_POINTER_DOWN: {

      final int pointerIndex = (action & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;

      // find which cell the initial touch took place in
      int x = (int)ev.getX(pointerIndex)/cellSize;
      int y = (int)ev.getY(pointerIndex)/cellSize;

      // exclude touches outside the grid
      if(x < 0 || x >= GRID_WIDTH || y < 0 || y >= GRID_HEIGHT) return true;

      sendTouchOSC(x, y, 1);

      TouchStream subsequent = new TouchStream(x, y, pointerIndex);

      list.add(subsequent);
      break;
    }

    case MotionEvent.ACTION_MOVE: {
      Iterator<TouchStream> iter = list.iterator();
      while(iter.hasNext()){

        TouchStream temp = iter.next();
        // Find the index of the active pointer and fetch its position
        final int pointerIndex = ev.findPointerIndex(temp.getId());
        final int x = (int) (ev.getX(pointerIndex)/cellSize);
        final int y = (int) (ev.getY(pointerIndex)/cellSize);

        // if dragged outside the grid
        if(x < 0 || x >= GRID_WIDTH || y < 0 || y >= GRID_HEIGHT){

          // send the last stored position
          sendTouchOSC(temp.getX(), temp.getY(), 0);
          return true;
        }

        // if we leave the previous square
        if(x != temp.getX() || y != temp.getY()){
          //send leave message
          sendTouchOSC(temp.getX(), temp.getY(), 0);
          // change current square coordinates
          temp.setX(x);
          temp.setY(y);
          sendTouchOSC(x, y, 1);
        }
      }
      break;

    }

    case MotionEvent.ACTION_UP: {

      // this should only be the remaining item
      if(list.size() != 0){
        TouchStream temp = list.get(0);
        sendTouchOSC(temp.getX(), temp.getY(), 0);
        list.remove(0);
      }
      break;
    }
    case MotionEvent.ACTION_POINTER_UP: {

      // Extract the index of the pointer that left the touch sensor
      final int pointerIndex = (action & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;

      Iterator<TouchStream> iter = list.iterator();
      while(iter.hasNext()){
        TouchStream temp = iter.next();
        if(temp.getId() == pointerIndex){
          sendTouchOSC(temp.getX(), temp.getY(), 0);
          iter.remove();
        }
      }

      break;
    }
    }

    return true; 
  } 

  // click handler for button grid
  // actionCode: 1 down, 0 up
  public void sendTouchOSC(int posX, int posY, int actionCode) {
    Object[] oscArgs = {new Integer(posX), new Integer(posY), new Integer(actionCode)};
    OSCMessageOut touchMsg = new OSCMessageOut("/" + prefix + "/press", oscArgs);
    sendOSCMessage(touchMsg);
  }

  // send OSC messages about phone orientation
  public void sendTiltOSC(int xTilt, int yTilt) {
    if(sendingTiltOSC){
      //tidy up messages
      if(xTilt < 0) xTilt = -xTilt;
      if(yTilt < 0) yTilt = -yTilt;
      if(xTilt > 255) xTilt -= 256;
      if(yTilt > 255) yTilt -= 256;

      Object[] oscArgs = {xTilt, yTilt};
      OSCMessageOut oscMsg = new OSCMessageOut("/" + prefix + "/tilt", oscArgs);
      sendOSCMessage(oscMsg);
    }
  }
  
  
  // getters and setters
  public void setDeviceIPAddress(String deviceIPAddress) {
    this.deviceIPAddress = deviceIPAddress;
  }

  public void setHostIPAddress(String hostIPAddress) {
    this.hostIPAddress = hostIPAddress;
  }

  public String getHostIPAddress() {
    return this.hostIPAddress;
  }

  public String getPrefix(){
    return this.prefix;
  }

  public void l(Object i){
    Log.i("Test", i.toString());
  }

  // find device screen size so as to draw 
  // grid correctly
  @Override
  public void onWindowFocusChanged (boolean hasFocus){
    cellSize = this.getWidth()/GRID_WIDTH;
  }

  // send a OSC message over the network
  private void sendOSCMessage(OSCMessageOut msg){
    try {
      oscPortOut.send(msg);
    } catch (IOException e) {
      Log.e("IOException", e.toString());
    }
  }
  
  // turn reporting of tilt messages on or off
  public void setTiltMode(boolean sendTiltOSC){
    this.sendingTiltOSC = sendTiltOSC;
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.