Continuos Vibrate and Music Alert until Confirmation : update

I had recently thought I solved my issue with creating a continuous vibrate and music alert for the BlackBerry application that I created for work. Unfortunately, when I put the fix on to the phone, the volume level of the music was very low, even though I had the volume set to 100%. So, it was back to the drawing board to try and figure out how to get this working. The main issue was determining if the music had finished and then starting it again until the user pressed a key.

After messing around with NotificationsEngineListener, Event and the Notifications Demo for what seemed like forever and continuing to get thread errors and other issues, it was a simple step back and regroup that helped me see the light. Instead of trying to kick off an event and a listener for the Notification, all I had to do was immediately kick off the Notification.

NotificationsManager.triggerImmediateEvent(bbhAttribute.NOTIFICATION_MESSAGEPAGE, 0, null, null);

I was already checking to see when the music had finished to determine if I needed to stop or continue. So, the simple step was to put the triggerImmediateEvent in the check.

public void audioDone(int reason)
{
	System.out.println("audioDone function");
	
	switch(reason) {
		case REASON_KEY_PRESSED:
			//System.out.println("Key Pressed.  Stopping Alert");
			stopAlert();
			break;
		case  REASON_COMPLETED:
			//System.out.println("Completed Called.  Stopping Alert");
			NotificationsManager.triggerImmediateEvent(bbhAttribute.NOTIFICATION_MESSAGEPAGE, 0, null, null);
			continueAlert();
			break;
		case REASON_STOP_CALLED:
			//System.out.println("Stop Called.  Do Nothing.");
			// Do nothing
			break;
	}
}

Which basically means, the initial music and vibrate will play and then when they are done and the user hasn’t clicked a button to stop it, the Notification will start before the music and vibrate plays again.

So far, this seems to be the working solution. I hope this is the final solution, because it has been a headache. I hope the BB10 method of notify users has something simple for continuous notification.

Continuos Vibrate and Music Alert until Confirmation

The main phone application that I support at work gets data pushed to it. Part of the data is a Message Page to notify the technician that they have a service call assigned or needing attention. Due to the nature of the service calls, the technician needs this alert to continually go off until they acknowledge the alert. A while back I changed the pop up message to a global message, which makes the pop up show on all screens, regardless if the user is in the application.

public static void displayGlobalMessage(final String gMessage)
{
	UiApplication.getUiApplication().invokeLater( new Runnable() {
			public void run() {
				UiEngine uie = Ui.getUiEngine();
				alertDialogListener  closeListener = new alertDialogListener();
				
				Dialog screen = new Dialog(Dialog.D_OK, gMessage, Dialog.OK,
											Bitmap.getPredefinedBitmap(Bitmap.EXCLAMATION),
											Manager.VERTICAL_SCROLL);
				screen.setDialogClosedListener(closeListener);
				uie.pushGlobalScreen(screen, 1, UiEngine.GLOBAL_MODAL);
			}
	});
}

Unfortunately, when I created this option, I some how broke my continuous alert that was previously setup. After many attempts to get it to work again, including using a TimerTask, I finally got the alert to work again.

The first part is creating the AlertListener class that I will use to handled starting the music and vibrate. This was the most important part, because stopping and starting the alert depends on what is to be called. It took a very long time to figure out when to turn off the overall alert (continueAlert) and when to turn on and off the music and vibrate (audioFinished). This is handled in the audioDone function, because the music plays longer than the vibration (which is why nothing is done on vibrateDone and buzzerDone).

public class SDAAlertListener implements AlertListener
{
    private boolean continueAlert;
    private Object continueAlertLock;
    private boolean audioFinished;
    private Object audioFinishedLock;
    
    public SDAAlertListener()
    {
    	//System.out.print("Added Continuos Alert Listener");
        continueAlert = true;
        continueAlertLock = new Object();
        audioFinished = false;
        audioFinishedLock = new Object();
    }
    
    public void startAlert()
    {
    	//System.out.println("Starting Contiuous Alert");
    	SetContinueAlertStatus(true);
    	SetAudioDoneStatus(false); 
    	
    	Alert.startAudio(music.myFogHornTune, 8);
    	Alert.startVibrate(500);
    }
    
    public void continueAlert()
    {
    	//System.out.println("Contiuous Alert to Continue");
    	SetContinueAlertStatus(true);
    	SetAudioDoneStatus(false); 
    	
    	Alert.startAudio(music.myFogHornTune, 8);
    	Alert.startVibrate(500);
    }
    
    public void stopAlert()
    {
    	//System.out.println("Stopping Contiuous Alert");
    	SetAudioDoneStatus(true); 
    	SetContinueAlertStatus(false);
    	
    	Alert.stopAudio();
        Alert.stopBuzzer();
    }
    
    public boolean GetContinueAlertStatus()
    {
        synchronized(continueAlertLock)
        {
            //System.out.println("Getting continueAlertStatus.");
            return continueAlert;
        }
    }
    
    public boolean GetAudioDoneStatus()
    {
        synchronized(audioFinishedLock)
        {
            //System.out.println("Getting buzzerFinished.");
            return audioFinished;
        }
    }
    
    public void SetContinueAlertStatus(boolean value)
    {
    	synchronized(continueAlertLock)
        {
        	//System.out.println("Setting ContinueAlert to " + value);
        	continueAlert = value;
        }
    }
    
    public void SetAudioDoneStatus(boolean value)
    {
        synchronized(audioFinishedLock)
        {
            //System.out.println("Setting audioFinished to " + value);
            audioFinished = value;
        }
    }
    
    public void audioDone(int reason)
    {
    	System.out.println("audioDone function");
    	
    	switch(reason) {
	    	case REASON_KEY_PRESSED:
	    		//System.out.println("Key Pressed.  Stopping Alert");
	    		stopAlert();
	    		break;
	    	case  REASON_COMPLETED:
	    		//System.out.println("Completed Called.  Stopping Alert");
	    		continueAlert();
	    		break;
	    	case REASON_STOP_CALLED:
	    		//System.out.println("Stop Called.  Do Nothing.");
	    		// Do nothing
	    		break;
    	}
    }
    
    public void buzzerDone(int reason)
    {
        // Do nothing.
    }
    
    public void vibrateDone(int reason)
    {
        // Do nothing.
    }
}

The next step is to create an instance of the listener on the main screen, so it is always there. This was one of the issues I was having, because I was adding the listener when the Message Page came in and then removing it after the alert was done. By creating the single listener, I only worry about starting and stopping the music and vibrate.

// Before the main screen is created
public static SDAAlertListener _sdaAlertListener = new SDAAlertListener();
// After the application is created and is only called once
((Application) UiApplication.getUiApplication()).addAlertListener(StartScreen._sdaAlertListener);

Next, I handled the Message Page by sending it to the GlobalMessage display function and creating a loop to check for when the Alert should be played again. The loop checks the Continue Alert Status to see if the button click hasn’t turned it off. Then it checks to see if the audio is done playing. If the Continue Alert is true and the Audio Done is true, then the startAlert function is called again to replay the music and vibration. Otherwise a break stops the loop.

/* Global Dialog display instead of screen pop */
bbhUtil.displayGlobalMessage("New Message Page " + MessagePagingInfo.getCurrentMessage());     
// Start Continuous paging section 
boolean alertStatus = true;
StartScreen._sdaAlertListener.startAlert();
// Start loop 
while (true)
{ 
	alertStatus = StartScreen._sdaAlertListener.GetContinueAlertStatus();
	if(alertStatus)
	{
		if(StartScreen._sdaAlertListener.GetAudioDoneStatus()) {
			//System.out.println("Audio Done Status is True");
			StartScreen._sdaAlertListener.startAlert();
		} else {
			break;
		}
	}
	else
	{ 
		System.out.println("Paging Alert Stop.");
		break;
	}                               
}

Finally, the Global Message display has a close listener attached to it. This listener calls the Alert stop function when the user clicks the “OK” button.

public class alertDialogListener implements DialogClosedListener {
	public void dialogClosed(Dialog dialog, int choice) {
		// Check for OK click and then stop Timer
		//System.out.println("Output Choice: " + choice);
   		 switch (choice) {
   		 	case Dialog.OK : 
   		 		synchronized(UiApplication.getEventLock())
   		 		{
   		 			//System.out.println("Calling Alert Listener Stop");
   		 			StartScreen._sdaAlertListener.stopAlert();
                }
        		break;
            case Dialog.CANCEL : 
            	Status.show("Cancel msg"); 
            	break;
        }
	}
}

This also allows for multiple Message Page alerts, since it turns on and off the same listener. I just wish I hadn’t taken so long in figuring it out.