In a previous post, I stated that when you press the stop button on your player, you have 2 seconds to continue to execute code before the player shuts down.  But, that statement needs to be qualified.  If you try to delay the application_end (or the deprecated stop_request) event by calling preventDefault when the user has pressed the stop, eject, or power button, the player will stop permitting preventDefault after two seconds.  If you do not call preventDefault, you have a single tick to execute your code.  This means that the function that handles the application_end event will be called, but not any callbacks that would have been handled in subsequent ticks.  This is why using setContentInformation works, but trying to write your own XML file will not execute to completion.

However, if you just add a call to preventDefault to the event handler, and the application_end is actually triggered by the title end (and not the user pressing stop), you will end up creating an infitite loop.  So, if you want to use preventDefault to allow more execution time, make sure to include an exit point in your script so that the application can end when your script is complete.

Below is an example of how the previous project would be modified if you were to call preventDefault on the application_end event:

addEventListener("application_end", handleApplicationEnd, false);

/******************************
  BEGIN ADDED CODE
********************************/
//end sequence status
var endSeq = {
  initialized:false,
  complete:false
};
/******************************
  END ADDED CODE
********************************/

function setResume( time )

  try
  {
    //set key for resume time
    psd.setContentInformation(contentID, resumeKey, time, setContentInfoCB);
  }
  catch(ex)
  {
/******************************
  BEGIN ADDED CODE
********************************/
    //set end sequence to complete
    endSeq.complete = true;
/******************************
  END ADDED CODE
********************************/
    TraceError("EXCEPTION on setContentInformation", ex, arguments.callee);
  }
 
  function setContentInfoCB( result, key )
  {
    if ( result == PersistentStorageManager.SUCCEEDED )
    {
        TraceInfo("SUCCEEDED on setContentInformation", arguments.callee);
    }
    else
    {
        TraceInfo("FAILED on setContentInformation", arguments.callee);
    }
/******************************
  BEGIN ADDED CODE
********************************/
    //set end sequence to complete
    endSeq.complete = true;  
/******************************
  END ADDED CODE
********************************/
  }
}

function handleApplicationEnd(evt)
{

/******************************
  BEGIN ADDED CODE
********************************/
    //end sequence complete, exit
    if (endSeq.complete) return;
   
    //prevent end for another tick
    evt.preventDefault();

    //end sequence initialized, exit
    if (endSeq.initialized) return;
   
    endSeq.initialized = true;
/******************************
  END ADDED CODE
********************************/
   
    //event should pass value time based on title timeline
    //if not, use elapsedTime
    //this value could be equal to or greater than the movie runtime,
    //check for this before using value in resume
    var time = evt.time && (evt.time).match(timeCodeRegEx) ? evt.time : Player.playlist.currentTitle.elapsedTime;   
    setResume(time);   
}