Android “ended” and “pause” events on <video>

In working on implementing playlists for the Brightcove Smart Players, I discovered some pretty annoying discrepancies between the HTML5 video specification and how Android handles video objects.  I’ve created a droidfix GitHub repository which captures an example of how to solve these problems.

The Problems

On Android devices, similar to the iPhone and iPod touch, video is a modal experience; that is, rather than playing the video within the context of the page, the video is immediately expanded to a full-screen experience. We can debate whether this approach is right or wrong all day long if you’d like; but for now let’s just accept it and move on.

On the Android platform, the video player is opened as if it were a new page. To return to the page from the playing (or paused) video, the user must use the device’s back button.  Several things do (or don’t) happen when you hit the back button:

  1. An “ended” event fires
  2. The currentTime property of the video is reset to 0
  3. A “pause” event does not fire

The ended event is particularly troubling when building a playlist-driven player as the ended event can be used to signal to the playlist that it’s time to load the next video. It creates a funny (for the developer; probably not the user) inescapable scenario when the user pauses the video and the next item on the playlist loads immediately until the end of the playlist is reached.

Workaround

I’ll point you to the GitHub version of droidfix.js to see the code; including an example page showing the code in action. Here’s a quick description of the workaround:

First, when timeupdate events are fired, we store the furthest forward position in the video that has played. We have to do this because of item #2 above; once the video actually ends, we’ll lose the last time index.

Now, when an ended event is received, we check to ensure the video has really reached the state specified for an ended event. In other browsers, we check that the currentTime property of the video is equal to the video’s duration; if that’s true, we’ve reached the end of the video.  For android, we check that the furthest forward position variable we stored earlier is within 2 seconds of the end of the video. Why 2 seconds? Well, the Android browser doesn’t fire a timeupdate event at the end of the video; furthermore, it also doesn’t seem to be consistent as to how far from the end of the video it fires its last timeupdate. In my testing, 2 seconds was a long enough buffer to include all examples; it also has the side-effect of being short enough that we can reasonably assert that beyond that point, the user has “completed’ the video.

If we determine that the ended event is legit, we fire a series of custom listeners set up in droidfix. However, if we determine this is android telling us that the video has ended when it hasn’t, we create a custom pause event and fire it so handlers bound to pause will be triggered.

Go fork and wreak havoc!

I put the example code on GitHub with a pretty descriptive README of how it works along with the current known issues / caveats. Feel free to grab it, modify, comment, etc. If nothing else, it provides an example that you can integrate with your own video solutions.

Incredibly Strange iOS Issue

Update 8/19/2010 @ 11:55 EDT

It looks like this may be a cross-domain issue after all.  I changed my testing methodology and was able to reproduce this issue without Gmail being involved. That’s the good news, the bad news is that even in a cross-domain scenario, access should simply be denied to the properties or an exception should be thrown.  In this case in Mobile Safari, the script dies at the point in execution where it attempts to access the property.

</update>

I’m posting this to my blog in hopes of finding some help; I’d love to file this issue as a bug report but I have no idea if it’s a bug in Gmail or a bug in Mobile Safari.  I’m inclined to think the latter; but the fact that I can consistently reproduce this issue in the manner described below leads me to think it could be something crazy that Gmail does.

Window.opener

The window.opener object is available on browser windows that have been spawned by other browser windows (either using Javascript or the classic target=”_blank”). It’s a reference to a window object. In general, it behaves entirely as expected on the iOS; except when you click a link from Gmail (and the issue occurs whether you’re using the Mobile Gmail version or the desktop version on an iOS device).

What Happens?

Clicking a link from Gmail on an iOS device causes the link to open in a new browser window. However, if you have a page that attempts to reference any properties of the window.opener object, you’ll receive the error:

TypeError: no default value

Here’s where it gets really strange, if I evaluate the window.opener object itself in any way, it reports that its a DOMWindow object. However, if I try to enumerate the properties of that object none are found.  If I try to access a property of a DOMWindow object by name, I receive the above error.

What I’ve Tried

I’ve tried and ruled out several possible methods of reproducing this issue without Gmail; in each case the window.opener object behaved normally and I was able to both enumerate the properties and read a property directly without an error:

  • I created a page with a link using target=”_blank”
  • I created a page using Javascript’s window.open to open a link
  • I hosted the pages on different domains to see if there was some cross-domain issue affecting it.

I’ve also tried a few workarounds; none of which prevented the error:

  • Check for the presence window.opener.location (or any specific property) before using it in an assignment.
  • Wrapping any references to properties of window.opener in a try / catch.

At this point, I’m pretty well stumped on what’s happening here; or if there’s any way for me to work around it.  I’ve set up a demo that I encourage you to email to yourself so you can see this bug in action.   Turn on the debug console in MobileSafari, click that link from the gmail web app, and you’ll see the errors.  Click that link from anywhere else, you’ll get every property of the window.opener object written to your console.

You can test this on the devices themselves or the emulators; the behavior is consistent.

One more thing…

It just wouldn’t be an Apple-related post without that line; Once you see the error, tap the icon to switch browser windows.  Safari will crash.

Adobe’s Open Screen Project: What does it mean?

Adobe today announced the creation of the Open Screen Project to help facilitate the adoption of Flash and Flash-based technologies on a wide range of platforms. There’s plenty of coverage out there today about this initiative–and it’s no surprise. For years developers have been calling for an opening up of Flash and it looks like Adobe is ready to give it to us.

The big takeaway: Developers are now free to create their own versions of Flash Player.

First, this is fantastic news for the open source community and projects like Ubuntu who now have the opportunity to create a true “free software” version of the Flash player. Free software purists around the world rejoice!

But there’s more to it than just Free Software. Apple’s current SLA for the iPhone SDK would not allow Adobe’s Flash Player to be ported to the iPhone platform (barring special exception, which I’m not entirely convinced Apple would be unwilling to give). Could Apple develop its own version of Flash Player optimized for the iPhone? The Open Screen Project certainly looks that way–and I honestly can’t help but wonder if that’s part of the reason Adobe’s decided that now is the proper time to announce this project. Given the number of partners (and the conspicuous-in-their-absence-Apple) I’d hesitate to say that the iPhone SDK was a cause for this action; but it certainly may have influenced the timing. One thing’s for certain; it very much puts the ball back into Apple’s court on the issue of Flash on the iPhone.

I am one of the camp that believes Apple has no interest in seeing Flash on the iPhone. Flash competes too directly with a major Apple technology–Quicktime–for Apple to want to see it there. That said, with the onus now on Apple with regard to Flash on the iPhone, I think the boys at Adobe might have out-maneuvered ol’ Steve on this one.

And that might be the most impressive part of it all.