Android Open Source - HeadphoneController H C State Machine






From Project

Back to project page HeadphoneController.

License

The source code is released under:

GNU General Public License

If you think the Android project HeadphoneController 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

/*
 * TODO: license//from  w ww .j a v  a2 s.c o  m
 */

package ca.mbabic.headphonecontroller.statemachine;

import java.lang.Thread.State;
import java.util.concurrent.Semaphore;

import android.util.Log;
import ca.mbabic.headphonecontroller.services.MediaButtonListenerService;

/**
 * State machine keeping track of the state of the button presses.
 * Implementation of the State Pattern. See:
 * http://sourcemaking.com/design_patterns/state
 * 
 * @author Marko Babic
 */
public class HCStateMachine {

  /**
   * Reference to MediaButtonListenerService such that after command execution
   * we can re-register ourselves as exclusive media button player listener.
   */
  private static MediaButtonListenerService listenerService;
  
  /**
   * Class specific logging tag.
   */
  private static final String TAG = ".statemachine.HCStateMachine";

  /**
   * Interval to wait between button presses.
   */
  // TODO: make configurable
  private static final long BTN_PRESS_INTERVAL = 400;

  /**
   * Instance of HCStateMachine available to the application.
   */
  private static volatile HCStateMachine instance = null;

  /**
   * Reference to the state in which the machine is currently in.
   */
  private static HCState currentState;

  /**
   * The starting state of the machine.
   */
  private static HCState startState;

  /**
   * Time left until count down thread will execute the current state's
   * command.
   */
  private static long timeToExecution;

  /**
   * The amount of time the count down thread will sleep between acquiring the
   * semaphore and updating timeToExecution.
   */
  private static final long SLEEP_INTERVAL = 100;

  /**
   * Semaphore used to lock access to shared variable timeToExecution.
   */
  private static Semaphore countDownSemaphore = new Semaphore(1);

  /**
   * Thread in which the count down to execution monitoring functionality is
   * implemented.
   */
  private Thread countDownThread;

  static Runnable countDownRunnable = new Runnable() {

    public void run() {

      timeToExecution = BTN_PRESS_INTERVAL;

      while (timeToExecution > 0) {

        try {
          Thread.sleep(SLEEP_INTERVAL);
          countDownSemaphore.acquire();
          timeToExecution -= SLEEP_INTERVAL;
        } catch (InterruptedException ie) {
          Log.e(TAG, "Coundown thread interrupted!");
          return;
        } finally {
          countDownSemaphore.release();
        }

      }

      // Count down expired, execute current state's command.
      // TODO: this should be synchronized ... and we should take one
      // last check here to make sure timeToExecution <= 0 and if not
      // start looping again and not execute anything ...
      currentState.executeCommand();
      listenerService.registerAsMediaButtonListener();
      currentState = startState;
    }

  };

  /**
   * Private constructor. Get global application reference to state machine
   * via getInstance().
   */
  private HCStateMachine() {
    startState = new InactiveState();
    currentState = startState;
  }

  public void setService(MediaButtonListenerService mbls) {
    listenerService = mbls;
  }
  
  /**
   * @return Singleton instance of HCStateMachine.
   */
  public static HCStateMachine getInstance() {
    if (instance == null) {
      synchronized (HCStateMachine.class) {
        // Double check instance locking
        if (instance == null) {
          instance = new HCStateMachine();
        }
      }
    }
    return instance;
  }

  /**
   * Indicate to state machine that the media button has been pressed on the
   * headphones. TODO: keep track of long clicks... should not transition to
   * next state at end of such a command.
   */
  public void keyUp() {
    makeStateTransition();
  }

  /**
   * Transition to next state as appropriate given currentState.
   */
  private void makeStateTransition() {

    HCState nextState = currentState.getNextState();

    if (currentState.isTerminal()) {
      stopCountDownToExecution();
      currentState.executeCommand();
      currentState = startState;
    } else {
      currentState = nextState;
      startCountDownToExecution();
    }
  }

  /**
   * Call to start or reset a count down to execution of the current state's
   * command.
   */
  private void startCountDownToExecution() {

    try {

      countDownSemaphore.acquire();

      if (countDownThread == null
          || countDownThread.getState() == State.TERMINATED) {

        countDownThread = new Thread(countDownRunnable);
        countDownThread.start();
      } else {
        timeToExecution = BTN_PRESS_INTERVAL;
      }

    } catch (Exception e) {
      Log.e(TAG, e.toString());
    } finally {
      countDownSemaphore.release();
    }
  }

  /**
   * Called to cancel count down to execution thread.
   */
  private void stopCountDownToExecution() {

    countDownThread.interrupt();
    try {
      countDownThread.join();
    } catch (Exception e) {
      Log.e(TAG, e.toString());
    }

  }

}




Java Source Code List

ca.mbabic.headphonecontroller.ConfigurationFragment.java
ca.mbabic.headphonecontroller.HCApplication.java
ca.mbabic.headphonecontroller.HomeActivity.java
ca.mbabic.headphonecontroller.SelectCommandActivity.java
ca.mbabic.headphonecontroller.commands.CommandExecutor.java
ca.mbabic.headphonecontroller.commands.HCCommandContext.java
ca.mbabic.headphonecontroller.commands.HCCommandFactory.java
ca.mbabic.headphonecontroller.commands.HCCommand.java
ca.mbabic.headphonecontroller.commands.MuteMusicCommand.java
ca.mbabic.headphonecontroller.commands.NoOpCommand.java
ca.mbabic.headphonecontroller.commands.PlayPauseCommand.java
ca.mbabic.headphonecontroller.commands.PreviousCommand.java
ca.mbabic.headphonecontroller.commands.SkipCommand.java
ca.mbabic.headphonecontroller.configuration.HCConfigAdapter.java
ca.mbabic.headphonecontroller.configuration.HCConfigConstants.java
ca.mbabic.headphonecontroller.db.DbHelper.java
ca.mbabic.headphonecontroller.db.HCCallStateTable.java
ca.mbabic.headphonecontroller.db.HCCommandCallStateTable.java
ca.mbabic.headphonecontroller.db.HCCommandTable.java
ca.mbabic.headphonecontroller.db.HCDbAdapter.java
ca.mbabic.headphonecontroller.db.HCDbHelper.java
ca.mbabic.headphonecontroller.db.HCDbTable.java
ca.mbabic.headphonecontroller.db.HCInputSequenceCommandsTable.java
ca.mbabic.headphonecontroller.db.HCInputSequenceTable.java
ca.mbabic.headphonecontroller.models.HCCmd.java
ca.mbabic.headphonecontroller.models.HCInputSequence.java
ca.mbabic.headphonecontroller.services.MediaButtonListenerService.java
ca.mbabic.headphonecontroller.services.MediaButtonReceiver.java
ca.mbabic.headphonecontroller.services.MediaStateChangeReceiver.java
ca.mbabic.headphonecontroller.statemachine.FourPressState.java
ca.mbabic.headphonecontroller.statemachine.HCStateMachine.java
ca.mbabic.headphonecontroller.statemachine.HCState.java
ca.mbabic.headphonecontroller.statemachine.InactiveState.java
ca.mbabic.headphonecontroller.statemachine.OnePressState.java
ca.mbabic.headphonecontroller.statemachine.ThreePressState.java
ca.mbabic.headphonecontroller.statemachine.TwoPressState.java
ca.mbabic.headphonecontroller.views.CommandAdapter.java