Skip to the content.

How to turn the Propositional Production System (PPS) for a button into code

The code implementation should spiritually follow the PPS; that is, your code should only take action when moving from state to state (along the arrows in the PPS). This behavior is best represented by a switch statement, where each case represents a state in our PPS. Within each case, there can be nested if statement to handle transitioning to another state.

Each case should be broken out of and should properly handle input, propagating input to later views or stopping the input propagation as necessary. We typically do this through the onTouchEvent method. In onTouchEvent, returning true will stop the input propagation to views below it, while returning false allows views below it to handle the event.

Button Examples

Given the essential geometry for this button is:

and methods for that will be used are:

The PPS for this interaction is as follows:

stateDiagram-v2 [*] -->PRESSED: DOWN/Inside?
>indentButton() PRESSED --> PRESSED: MOVE/Outside?
>normalButton() PRESSED --> [*]: UP/Outside?
cancelAction() PRESSED --> [*]: UP/Inside?
invokeAction() PRESSED --> PRESSED: MOVE/Inside?
indentButton()

The code is generated thusly

@Override
public boolean onTouch(MotionEvent e) {
  EssentialGeometry geometry = essentialGeometry(event);
  switch (state) {
    case State.START:
      if (geometry == Geometry.INSIDE && e.getAction() == MotionEvent.ACTION_DOWN) {
         indentButton();
         state = State.PRESSED;
         return true;
      }
      break;
    case PRESSED
      if (e.getAction() == MotionEvent.ACTION_MOVE) {
        if (geometry == Geometry.INSIDE) {
          indentButton();
    	  } else {
          normalButton();
        }
        return true;
      }
      else if (e.getAction() == MotionEvent.ACTION_UP) {
        state = State.START; // note we don't actually use the END state
        if (geometry == Geometry.INSIDE) {
          invokeAction();
        } else {
          cancelAction();
        }
        return true;
      }
      break;
    default:
      break;
  }
  return false;
}