5

I have a timer app and I want to vibrate the phone once the timer has finished. I can currently play a sound until the OK button is pressed, but it only vibrates once. How can repeat the vibration until the user presses the OK button?

This is my current code

SoundEffectInstance alarmSound = PlaySound(@"Alarms/"+alarmSoundString);

VibrateController vibrate = VibrateController.Default;

vibrate.Start(new TimeSpan(0,0,0,0,1000));

MessageBoxResult alarmBox = MessageBox.Show("Press OK to stop alarm", "Timer Finished", MessageBoxButton.OK);

if (alarmBox == MessageBoxResult.OK)
{
    alarmSound.Stop();
    vibrate.Stop();
}

UPDATE: I have tried Joe's response, which works if I don't call MessageBox.Show() It seems to stop at this point until OK is pressed.

Chris
  • 3,036
  • 5
  • 36
  • 53

2 Answers2

2

VibrateController.Start(Timespan) will throw an error if you pass a value greater than 5 seconds in, so you need to do some trickery to keep it going. Create a timer, and set it to restart the vibration. For example:

edited

Silly me, I forgot that both Messagebox, and DispatcherTimer will run on the same thread. The Messagebox will block it. Try this.

public partial class MainPage : PhoneApplicationPage
{
    TimeSpan vibrateDuration = new TimeSpan(0, 0, 0, 0, 1000);
    System.Threading.Timer timer;
    VibrateController vibrate = VibrateController.Default;
    int timerInterval = 1300;
    SoundEffectInstance alarmSound = PlaySound(@"Alarms/"+alarmSoundString);
    TimeSpan alramDuration; //used to make it timeout after a while

    public MainPage()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        timer = new Timer(new TimerCallback(timer_Tick), null, 0, timerInterval);
        alramDuration = TimeSpan.FromSeconds(0);
        alarmSound.Play();
        MessageBoxResult alarmBox = MessageBox.Show("Press OK to stop alarm", "Timer Finished", MessageBoxButton.OK);

        if (alarmBox == MessageBoxResult.OK)
        {
            StopAll();
        }
    }

    void timer_Tick(object sender)
    {
        //keep track of how long it has been running
        //stop if it has gone too long
        //otheriwse restart

        alramDuration = alramDuration.Add(TimeSpan.FromMilliseconds(timerInterval)); 
        if (alramDuration.TotalMinutes > 1)
            StopAll();
        else
            vibrate.Start(vibrateDuration);
    }

    void StopAll()
    {
        timer.Change(Timeout.Infinite, Timeout.Infinite);
        vibrate.Stop();
        alarmSound.Stop();
    }
}

So I am using a System.Threading.Timer instead of the Dispatcher. It is mainly the same, only a little less of an obvious API. Instead of calling Start() and Stop() you have to pass in a delay amount. To start it, pass in 0. It will keep going off every 1.3 seconds until you call Change() passing in Timeout.Infinite

A few things to note:

  • vibrate.Start(vibrateDuration) is only called from the tick event. That is because the Timer will immediately kick off.
  • Per Mystere Man's suggestion, I added a timeout. you will want something like this.
  • You might want to refactor, and clean up my sample
Community
  • 1
  • 1
  • I think the MessageBox.Show() interferes with this. If I remove the time and vibrate stop methods then its start to vibrate continuously after the OK button is pressed – Chris Dec 22 '11 at 18:00
  • @Chris if you remove the stops()s from the if statement? –  Dec 22 '11 at 18:30
  • if I remove the stop()s the phone starts vibrating after pressing the OK button – Chris Dec 22 '11 at 19:46
0
SoundEffectInstance alarmSound = PlaySound(@"Alarms/"+alarmSoundString);

VibrateController vibrate = VibrateController.Default;

var vibrationLength = 1000;
var startTime = DateTime.Now;
vibrate.Start(new TimeSpan(0,0,0,0,vibrationLength));

MessageBoxResult alarmBox = MessageBox.Show("Press OK to stop alarm", "Timer Finished", MessageBoxButton.OK);
var ok = false;

While (!ok){
  if (alarmBox == MessageBoxResult.OK)
  {
    ok = true;
  }
  else{
     if(startTime.AddMilliseconds(vibrationLength * 1.2) < DateTime.Now)
     {
        startTime = DateTimne.Now;
        vibrate.Start(new TimeSpan(0,0,0,0,vibrationLength));
     }
  }
}

alarmSound.Stop();
vibrate.Stop();

Roughly

I don't write code for windows phone so this may cause the phone to become unresponsive. But the general Idea is keep checking to see if the user has hit okay and if not if enough time has elasped since the last vibration has started to start a new one.

If you want it to pulse I would suggest using AddMilliseconds and add a length greater than the pulse length you want.

Using a timer instead

pretending you class looks like this

public class buzzz
{

   MessageBoxResult alarmBox;
   DispatchTimer alarmTimer = new DispatchTimer();
   var vibrationLength = 1000.0;
   var timerIncrease = 1.2;
   VibrateController vibrate = VibrateController.Default;

   public buzz()
   {
      alarmTimer.Interval = TimeSpan.FromMillseconds(vibrationLegnth * timerIncrease);
      alarmTimer.Tick += alarmTimer_Tick
   }
   public void startBuzz()
   {
       SoundEffectInstance alarmSound = PlaySound(@"Alarms/"+alarmSoundString);
       vibrate.Start(new TimeSpan(0,0,0,0,vibrationLength));
       alarmTimer.Start();
       alarmBox = MessageBox.Show("Press OK to stop alarm", "Timer Finished", MessageBoxButton.OK);
    }

    void alarmTimer_Tick(object sender, EventArgs e)
        {
           if(alarmBox == MessageBoxResult.OK)
           {
              alarmTimer.Stop();
              vibrate.Stop();
           }
           else
           {
               vibrate.Start(new TimeSpan(0,0,0,0,vibrationLength));
           }
        }
}
msarchet
  • 15,104
  • 2
  • 43
  • 66