0

I am trying to make it so my app plays a sound when I shake it. I think that my shake code works, but I am having trouble with the media player. I followed peceps' answer for shake and I used Chris' final answer for sound. Obviously I did not make it an onClick but onShake.

Here is my activity code. (only error I get is for mp)

package com.grifball.info;

import com.grifball.info.ShakeDetector.OnShakeListener;

import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.media.MediaPlayer;
import android.os.Bundle;

public class HammerActivity extends Activity {

private ShakeDetector mShakeDetector;
private SensorManager mSensorManager;

// Declare the MediaPlayer object
private MediaPlayer mMediaPlayer;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.hammer_page);

    // ShakeDetector initialization
    mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    mShakeDetector = new ShakeDetector();  

    mShakeDetector.setOnShakeListener(new ShakeDetector.OnShakeListener() {
        public void onShake() {
            // Initialize media player
            mMediaPlayer = MediaPlayer.create(HammerActivity.this, R.raw.hammer);

            // Add OnCompletionListener to release the 
            mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    mMediaPlayer.release();
  }
            });
            mMediaPlayer.start();
    });
    };

    @Override
    protected void onResume() {
      super.onResume();
      mSensorManager.registerListener(mShakeDetector,
          mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
          SensorManager.SENSOR_DELAY_UI);
    }

    @Override
    protected void onPause() {
      mSensorManager.unregisterListener(mShakeDetector);
      super.onStop();
    }}

This is my ShakeDetector code.

package com.grifball.info;

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;


/**
 * Listener that detects shake gesture.
 */
public class ShakeDetector implements SensorEventListener {


  /** Minimum movement force to consider. */
  private static final int MIN_FORCE = 10;

  /**
   * Minimum times in a shake gesture that the direction of movement needs to
   * change.
   */
  private static final int MIN_DIRECTION_CHANGE = 3;

  /** Maximum pause between movements. */
  private static final int MAX_PAUSE_BETHWEEN_DIRECTION_CHANGE = 200;

  /** Maximum allowed time for shake gesture. */
  private static final int MAX_TOTAL_DURATION_OF_SHAKE = 400;

  /** Time when the gesture started. */
  private long mFirstDirectionChangeTime = 0;

  /** Time when the last movement started. */
  private long mLastDirectionChangeTime;

  /** How many movements are considered so far. */
  private int mDirectionChangeCount = 0;

  /** The last x position. */
  private float lastX = 0;

  /** The last y position. */
  private float lastY = 0;

  /** The last z position. */
  private float lastZ = 0;

  /** OnShakeListener that is called when shake is detected. */
  private OnShakeListener mShakeListener;

  /**
   * Interface for shake gesture.
   */
  public interface OnShakeListener {

    /**
     * Called when shake gesture is detected.
     */
    void onShake();
  }

  public void setOnShakeListener(OnShakeListener listener) {
    mShakeListener = listener;
  }

  @Override
  public void onSensorChanged(SensorEvent se) {
    // get sensor data
    float x = se.values[SensorManager.DATA_X];
    float y = se.values[SensorManager.DATA_Y];
    float z = se.values[SensorManager.DATA_Z];

// calculate movement
float totalMovement = Math.abs(x + y + z - lastX - lastY - lastZ);

if (totalMovement > MIN_FORCE) {

  // get time
  long now = System.currentTimeMillis();

  // store first movement time
  if (mFirstDirectionChangeTime == 0) {
    mFirstDirectionChangeTime = now;
    mLastDirectionChangeTime = now;
  }

  // check if the last movement was not long ago
  long lastChangeWasAgo = now - mLastDirectionChangeTime;
  if (lastChangeWasAgo < MAX_PAUSE_BETHWEEN_DIRECTION_CHANGE) {

    // store movement data
    mLastDirectionChangeTime = now;
    mDirectionChangeCount++;

    // store last sensor data 
    lastX = x;
    lastY = y;
    lastZ = z;

    // check how many movements are so far
    if (mDirectionChangeCount >= MIN_DIRECTION_CHANGE) {

      // check total duration
      long totalDuration = now - mFirstDirectionChangeTime;
      if (totalDuration < MAX_TOTAL_DURATION_OF_SHAKE) {
        mShakeListener.onShake();
        resetShakeParameters();
      }
    }

  } else {
    resetShakeParameters();
  }
}
  }

  /**
   * Resets the shake parameters to their default values.
   */
  private void resetShakeParameters() {
    mFirstDirectionChangeTime = 0;
    mDirectionChangeCount = 0;
    mLastDirectionChangeTime = 0;
    lastX = 0;
    lastY = 0;
    lastZ = 0;
  }

  @Override
  public void onAccuracyChanged(Sensor sensor, int accuracy) {
  }

}

This is my OnCompletionListener code. package com.grifball.info;

import android.media.MediaPlayer;

public class OnCompletionListener {

public void onCompletion(MediaPlayer mp) {
    // TODO Auto-generated method stub

}

}
Community
  • 1
  • 1
pimpindacrib
  • 3
  • 1
  • 5
  • What do you mean by "only error I get is for mp"? – DigCamara Apr 04 '13 at 00:42
  • All the mp and mp.'s under onShake in the main activity. Look at chris' set up for audio, except it is under and onClick not onShake. "mp cannot be resolved" – pimpindacrib Apr 04 '13 at 00:59
  • Well... you need to declare it `private MediaPlayer mp;` underneath `private SensorManager mSensorManager;` But that is a compilation error... was that your problem? – DigCamara Apr 04 '13 at 01:05
  • now I get an error for " mp.setOnCompletionListener(new OnCompletionListener() {" The method setOnCompletionListener(MediaPlayer.OnCompletionListener) in the type MediaPlayer is not applicable for the arguments (new OnCompletionListener(){}) – pimpindacrib Apr 04 '13 at 01:08

2 Answers2

0

My guess is that you have mixed up interface and class here.

Your OnCompletionListener class is totally unnecessary. You can safely remove it unless you use it somewhere else in your code.

MediaPlayer.setOnCompletionListener() takes an interface of type MediaPlayer.OnCompletionListener as an argument. This interface already exists for you.

As for the rest of your code. You never declare your MediaPlayer object mp. It just suddenly appears inside onShake().

public class HammerActivity extends Activity {

private ShakeDetector mShakeDetector;
private SensorManager mSensorManager;

// Declare the MediaPlayer object
private MediaPlayer mMediaPlayer;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // ShakeDetector initialization
    mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    mShakeDetector = new ShakeDetector();  

    mShakeDetector.setOnShakeListener(new ShakeDetector.OnShakeListener() {
        public void onShake() {
            // Initialize media player
            mMediaPlayer = MediaPlayer.create(HammerActivity.this, R.raw.hammer);

            // Add OnCompletionListener to release the 
            mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    mMediaPlayer.release();
                }
            });
            mMediaPlayer.start();
        }
    });
}
Ole
  • 7,621
  • 2
  • 27
  • 34
  • I am going to have more than one page that does the same method, but i'll try this out – pimpindacrib Apr 04 '13 at 01:14
  • If that's the goal of your `OnCompletionListener` class, then I suggest you rename it. It kinda has an "interface name" at the moment, which only creates confusion ;) – Ole Apr 04 '13 at 01:32
  • Yup its still not working, I just want it to play a sound when I shake it =( – pimpindacrib Apr 04 '13 at 01:34
  • What kind of errors are you getting? Please post your updated code in your original post ;) – Ole Apr 04 '13 at 01:35
  • I am not getting any errors, it just isn't playing the sound when I shake it. – pimpindacrib Apr 04 '13 at 01:38
  • Have you done some logging to check that `onShake()` gets called when you shake your device? – Ole Apr 04 '13 at 01:41
  • You paste `Log.i("SomeTag", "Is this showing up in LogCat?")` inside `onShake()`, and watch the LogCat window as you run your application. Or you can set a breakpoint inside `onShake()` and see if you ever reach it. – Ole Apr 04 '13 at 01:55
  • I put it in there but can't seem to find it, I am using an actual phone, not emulator because im shaking it. This is the last part of my app and driving me insane. – pimpindacrib Apr 04 '13 at 02:05
  • Maybe we could chat another way or use Team Viewer, I am really frustrated. – pimpindacrib Apr 04 '13 at 02:16
0

Take the code below and move it to your onCreate() method

  mMediaPlayer = MediaPlayer.create(HammerActivity.this, R.raw.hammer);

            // Add OnCompletionListener to release the 
            mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    mMediaPlayer.release();
  }
            });

also look at the SensorManager documentation

protected void onResume() {
         super.onResume();
         mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
     }

     protected void onPause() {
         super.onPause();
         mSensorManager.unregisterListener(this);
     }

Mind you: I just cut and paste the code from the SensorManager documentation. You have to adapt it to your code; my main point is that your onPause declaration is wrong.

DigCamara
  • 5,352
  • 4
  • 33
  • 45