Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mobile support issues and some solutions #975

Closed
sangatpedas opened this issue Feb 2, 2014 · 35 comments
Closed

Mobile support issues and some solutions #975

sangatpedas opened this issue Feb 2, 2014 · 35 comments

Comments

@sangatpedas
Copy link

Hi guys,

I've been focussing on mobile support for videojs on the most popular Android browsers and find the following issues and some solutions. Mainly this is about support for the videojs controls.

First, in Chrome on Android all seems to work as expected.

The most problems occur with the default Android browser on Jelly Bean, ICS seems to be ok. Basically in the current version the controls of the standard browser in Jelly Bean don't work at all. The reason for this is that Browser generates multiple clicks. So for instance when the play button is clicked it calls the process twice, resulting in a play request followed immediately by a pause request, resulting in nothing really happening. The same goes for all other buttons in the control bar.

I'm sure my solutions won't meet the required quality of the project but I give them anyway so they can be used as temporary work-around by others. This is done by editing the dev version.

First I've defined more booleans so I better know what browser I deal with:

vjs.IS_FIREFOX = (/Firefox/i).test(vjs.USER_AGENT);
vjs.IS_CHROME = (/Chrome/i).test(vjs.USER_AGENT);
vjs.IS_OPERA = ((/Opera/i).test(vjs.USER_AGENT) || (/OPR/i).test(vjs.USER_AGENT));
if (!vjs.IS_FIREFOX && !vjs.IS_CHROME && !vjs.IS_OPERA) //the safari string is also used in other browsers
vjs.IS_SAFARI = (/Safari/i).test(vjs.USER_AGENT);

Next, I define an execution time out based on browser/platform:

var execTimeout=0;
if (vjs.TOUCH_ENABLED && vjs.IS_ANDROID && (vjs.IS_SAFARI || vjs.IS_FIREFOX))
var execTimeout=500; //this is the time in ms that allows for a next execution
var isExecuted=false;

Now basically all onclick function are rewritten like this:

// OnClick - Toggle between play and pause
vjs.PlayToggle.prototype.onClick = function(event){
   if(isExecuted==false || isExecuted==null) {
    isExecuted=true;
    if (this.player_.paused())  {
        this.player_.play();
    } else {
        this.player_.pause();
    }
    setTimeout(function() {isExecuted=false; }, execTimeout);
  }
};

On the fullscreen toggle button more changes are required. Since Safari uses native controls in fullscreen mode, any request from the toggle button is always a request for fullscreen. And since returning from fullscreen with native controls doesn't change the values of the button or the var isFullScreen, no need to change them in the first place.

vjs.FullscreenToggle.prototype.onClick = function(){
  if(isExecuted==false || isExecuted==null) {
    isExecuted=true;
    if (this.player_.isFullScreen==null) this.player_.isFullScreen=false;
    if ((vjs.TOUCH_ENABLED && vjs.IS_ANDROID && vjs.IS_SAFARI) || !this.player_.isFullScreen) {
        this.player_.play();
        this.player_.requestFullScreen();
    }
    else if (!this.player_.isFullScreen) {
        this.player_.requestFullScreen();
        this.el_.children[0].children[0].innerHTML = 'Non-Fullscreen'; // change the button text to "Non-Fullscreen"        
    } else {
        this.player_.cancelFullScreen();
        this.el_.children[0].children[0].innerHTML = 'Fullscreen'; // change the button to "Fullscreen"
    }
    setTimeout(function() {isExecuted=false; }, execTimeout);
  }
};

vjs.MuteToggle.prototype.onClick = function(){
    var _this = this;
    if(isExecuted==false || isExecuted==null) {
        isExecuted=true;
        _this.player_.muted( _this.player_.muted() ? false : true ); 
    }
    setTimeout(function() {isExecuted=false; }, execTimeout);
};

As for the volume slider, I don't see much use for it unless one is a midget with extremely small fingers.

Then there's a problem (in my opinion) once a player is paused. Most mobile browser show a play button in the middle but since vjs.MediaTechController.prototype.onTap only triggers user activity. Since Chrome and Opera show a big native play button I made the following changes:

vjs.MediaTechController.prototype.onTap = function(){
  this.player().userActive(!this.player().userActive());
     if ((this.player().paused()) && (vjs.IS_CHROME || vjs.IS_OPERA))
      this.player().play() ;
};

After having done these changes the following issues remain for Android:

Firefox:
fullscreen doesn't work, remote debugging shows the fullscreen request is ignored due to too many iterations. This corresponds with a test I did with an external button that requests a full change, which works.

Returning from fullscreen changes zoom mode, player is slightly bigger as if double clicked.

Safari (so the official Safari release on Android)
Any fullscreen requests is ignored and stops the video entirely from playing

Opera
First play always switches to fullscreen
returning from fullscreen the native controls show again, even the boolean is set to false.

Thanks for all the work you guys put in and I hope this helps a bit and obviously I hope you guys can help with some of the remaining issues.

Remco

@mmcc
Copy link
Member

mmcc commented Feb 4, 2014

Thank you for the detailed report! We think we've got a good idea where this is happening, but we'll need to do more testing to confirm. Could you tell us specifically what device / OS version you're using so we can try to replicate as closely as possible? Also, I was under the impression that the Android browser was removed entirely in 4.3?

I ran these tests on a Samsung Galaxy S4 running Android 4.3. Keep in mind I'm not a daily Android user, so please forgive any Android n00bery on my part :)

  • Firefox: The customControlsOnMobile option seems to get ignored, and there isn't a fullscreen option available at all in the controls. Do you have a demo on hand with either of these things working (that displays the issue you reported)? I was using the Firefox stable version from Play, not the beta.
  • Safari: AFAIK there was never an official Safari release for Android. Are you referring to "Safari Browser" app by a user named GALAXYS9? Either way, it's hard to say what's going on with fullscreen in the app, but considering the somewhat questionable legitimacy of the app (at least in terms of naming) we're not going to dedicate too much time to looking into it.
  • Opera: The native player takes over much like we see on Android and Windows Mobile phones, so there's not much we can do there.

@sangatpedas
Copy link
Author

Hi Matthew,

I haven't tested with 4.3 yet, I'm actually waiting for my Nexus 5 with 4.4. The tests I did so far were on a Sony Xperia with Android 4.1.2 and a Sony Tablet S with Android 4.0.x. I totally get that you guys focus on supporting the latest version and don't want to waste time with the bugs and problems of older version. However, I'm planning to use videojs in production in a country where they still sell Android 4.0 handsets and in general I think it's vital for a platform to deliver cross-browser compatibility.

I can easily provide you with a demo, but I'm pretty sure that the behaviour on 4.3 will be different on 4.1 (the platform I tested), the same as behaviour on 4.0 was different from 4.1.

Anyway, the problem of multiple clicks happening was in Browser on Android 4.1.2.

The summary of other problems across different browser also is based on tests on Android 4.1.2.

Next week I plan to do all tests again on Kit Kat and will share the results. For firefox, yeah I guess results from version 4.1 are less interesting for your developments.

As for Safari, I start to wonder now, if you search in Google for "safari browser android app" you can see it was in the playstore, but now has been removed so I guess it was a fake, my bad.

Anyway, I will do a lot more research/testing on mobile so I just share and hopefully it helps.

@heff
Copy link
Member

heff commented Feb 5, 2014

Very helpful, thanks!

@sangatpedas
Copy link
Author

Btw, I just checked and according to the device emulator in the ADT, the default browser is still included in both Android 4.3 and 4.4. However, I guess manufacturers can and do decide to feature Chrome as the main browser.

@gkatsev
Copy link
Member

gkatsev commented Feb 6, 2014

Nexus devices that began with the original Nexus 7 don't ship with any browser but Chrome. However, webviews on these devices are based on the "Native Android Browser". Starting with Android kitkat (4.4), webviews are based on chrome/chromium 18 (unfortunately, only 18, still better than nothing) and a lot of manufacturers are now starting to base their browsers based on chrome 18 as well. For example, the Samsung GS4's browser is based on chrome 18. Older samsung devices and other devices that have custom skins (i.e., non-nexus) probably have a custom browser based on the 'native android browser'.

Also, I'm not certain whether this is a related issue, but in #992 I fixed some problems with touch events and listening to those. It may or may not address the issues you were seeing, but worth taking a look.

@sangatpedas
Copy link
Author

Btw, here's a nice statistic on Android versions being used at the moment: http://images0.tcdn.nl/digitaal/article22270727.ece/BINARY/q/Google+Android+percentages.jpg

Seems that Android 4.1 still represent1 >36% of all devices, which is quite a big chunk.

@mmcc
Copy link
Member

mmcc commented Feb 7, 2014

Thanks for all of the feedback, @sangatpedas, this has been really helpful (that chart is great). We absolutely agree on the importance of backwards compatibility within reason, and the versions of Android we're talking about definitely fall in that range.

The PR @gkatsev mentioned has been merged into master, so would you mind testing against a fresh build and letting us know if that helped?

@sangatpedas
Copy link
Author

Hi @mmcc, I'd be happy to help you out here but I never made a fresh build myself yet. I kinda understand what's needed and generally how it works but maybe you can fill in the gaps for me a bit to make sure?

@sangatpedas
Copy link
Author

I'm sorry but I'm kinda oldskool dev guy so I'm now trying to figure out github so my contributions can be more effective. So I've forked the project and will debug using the source-loader.js. I'm just wondering if there's a quick way to create a fresh dev version.

@sangatpedas
Copy link
Author

Anyway, I made a test page using the source-loader.js and the js files in the folder src of the master branch. Please check if I'm using the right files. If so, the commits didn't solve the issue, in the default browser on Android one click still seems to generate two clicks resulting in nothing happening. This is the test page: http://video.sangatpedas.com/test-vjs-master

@xanatrobe
Copy link

Has there been any fix for this? I am using video.js in PhoneGap and it is causing all kinds of trouble with the play/pause issue.

@mmcc mmcc added bug and removed needs: more info labels Mar 4, 2014
@DomSkech
Copy link

Hello. I am experiencing this exact issue (I think) on some Samsung devices (Tab 3 and S4). Is the recommended fix to follow sangatpedas excellent solution or have updates been published to fix this?

@mmcc
Copy link
Member

mmcc commented May 20, 2014

@sangatpedas That demo example you showed works great for me. Does that include your fixes?

I'm pretty sure the answer here is going to be yes, but any chance anyone's tried this since version 4.5 was released? All problems still present?

@sangatpedas
Copy link
Author

@mmcc Hi Matt, I'm just picking up again on the player and will test whether the problem still exists on the latest version of videojs, I keep you posted.

@mmcc
Copy link
Member

mmcc commented Jul 25, 2014

Thanks @sangatpedas! Let us know what you find.

@nh0skkaj
Copy link

please share code demo for me?

@e-drakos
Copy link

e-drakos commented Dec 3, 2014

I had the same problem (video not pausing on tap on android) and in my case it was the handling of the touchevents that was the problem.
Specifically it was sending a touchend event that was not pausing the video but just showing/hiding the control bar.

i solved it by changing the 'touchend' event of the
vjs.MediaTechController.prototype.addControlsListeners function to:

this.on('touchend', function(event) {
this.onClick();
// Stop the mouse events from also happening
event.preventDefault();
});

and also changing the
vjs.MediaTechController.prototype.onClick function to play/pause if no event is present:

if (event!=null && event.button !== 0) return;

Its no elegant solution, and I guess the problem lies elsewhere, but it seems to work for me.

@mmcc
Copy link
Member

mmcc commented Dec 15, 2014

Now that we've got custom controls enabled by default for all devices, can we get confirmations as to whether or not we're still seeing problems here? I expected more new issues (particularly around Android) after we enabled them, but that hasn't really happened.

@tgreiser
Copy link

Galaxy Nexus 4.3 running Android Browser here. None of the video.js player examples work on my phone, including the homepage, the latest from git or the example @sangatpedas posted above.

The player and cover appear, but no video ever plays. The player turns grey, then turns black when something times out.

@anttimo
Copy link

anttimo commented Jan 8, 2015

@mmcc The multiple click issue with video player controls is still reproducible at least with default Android Browser on Samsung Galaxy S3 4.3. Also can be reproduced on Video.js landing page. When using native controls everything works correctly. Based on our Google analytics on one of our sites default Android browser is still as popular as Chrome browser so it would be nice to get this fixed.

@anttimo
Copy link

anttimo commented Jan 13, 2015

I assume double click issue could be also prevented by the ghost click busting method explained in this Google's article https://developers.google.com/mobile/articles/fast_buttons#ghost We actually used that method to stop these double clicks in one webview based app we made.

@ghost
Copy link

ghost commented Jan 18, 2015

I'm also having exactly same issue on Galaxy S3.. Video.js landing page video won't play at all on the S3 and my video player on my page is very intermittent. I get it to play by button mashing. Any single click to play just pauses itself again.

@NekR
Copy link

NekR commented Jan 19, 2015

I also can confirm that video.js is totally broken on Android 4.3 Default Browser (Galaxy Nexus). I also cannot play video on official site homepage, but I made local version of player and it starts to play (somehow through fullscreen), but video.js controls do not correctly -- always ghost/double click per one touch. It's very surprising for me to see such bug.

@NekR
Copy link

NekR commented Jan 19, 2015

https://github.com/videojs/video.js/blob/master/src/js/component.js#L1087
This does not works everywhere, especially on Android Stock Browser, so you need to mark that gesture as already processed as a click and do now process real click event.

Quick fix might look like this:

this.on('touchstart', function() {
  //...
  this.touchClickProcessed = false;
  this.preventNativeClick = false;
  //...
});

this.on('touchend', function() {
  //...
  if (allConditionsMeetAndLetThisClickHappen) {
     //...
     this.touchClickProcessed = true;
     //...
  } else if (doNotWantSimulatedTouchButAlsoDoNotWantRealClick) {
    this.preventNativeClick = true;
  }
});

this.on('click', function(e) {
  var ignoreClick = this.touchClickProcessed || this.preventNativeClick;

  this.touchClickProcessed = false;
  this.preventNativeClick = false;

  if (ignoreClick) {
    e.preventDefault();
    return;
  }

  //...
});

@csdougliss
Copy link

On my Samsung Galaxy Tab GT-P5200 I get a black background instead of a video. It plays fine without videojs?

@sangatpedas
Copy link
Author

I upgraded and then immediately rolled back, many many issues with this version. When using poster image you don't see the video play, just hear the sound. And I had some other issues.

@mmcc
Copy link
Member

mmcc commented Feb 4, 2015

@sangatpedas "And I had some other issues" isn't very helpful at all. Mind expanding on that? Even better, check and see if someone else has reported them, and if not, open a new one. We can't fix things we don't know about!

@sangatpedas
Copy link
Author

@mmcc Sorry mate but I was testing this in a production environment and as soon as I saw video wasn't showing I rolled back and kinda didn't care so much about the other problems. As far as I can remember the multiple click issue wasn't solved yet as well so I applied (a slightly modified) version of the code I posted initially in this thread. But like I said, at that moment I didn't bother to test a player that doesn't (consistently) show video. Anyway, didn't mean to be negative, me and all others appreciate what you guys are doing. If i have some time later I will do some checks and let you know.

@mmcc
Copy link
Member

mmcc commented Feb 4, 2015

Totally understandable! The core contributors just have a (relatively) limited device-set we can test on locally, so it's really helpful when we can get solid issue reports from the rest of the device world.

@sangatpedas
Copy link
Author

Hi Matthew,

Here are two things I encountered and our dev team will look into the reasons why it occurs. Here's the demo page of the latest videojs version and when you cut the query in the url it will revert to an older version of videojs. http://lv8.tv/the-salvation-official-us-release-trailer-1-2015-mads-mikkelsen-eva-green-movie-hd-12x6ony0l5cy.html?v=4.11.4

The older version works fine, the new version has some (major) issues but I suspect it might also be in our css or in one of the plugins.

  1. When played in Chrome on Android KitKat the poster doesn't disappear so you don't see the video play but you hear the sound.
  2. The resolution selector doesn't popup on mouse over anymore and basically can't function anymore. It opens on click but will disappear the moment the mouse leaves the button.

I don't see these problems on the videojs site so I guess css and plugins that worked with older versions are not compatible anymore with the latest version.

As said, we're looking into the cause and will update you later.

@sangatpedas
Copy link
Author

Hi Matthew,

An update from my side after testing V4.11.4:

  1. The problem described in this thread, a click generating multiple events, seems to be solved, also on older versions of Android.
  2. The problem with the poster might have come from a plugin as it doesn't occur when we test a version without any plugins. We easily solved it with:
    .video-js.vjs-android .vjs-poster { display: none; }
  3. The problem with the menu might be a bug as we had to override the mouse over event:
    $(document).ready(function(){
    $('.vjs-res-button.vjs-menu-button.vjs-control').on('mouseenter', function(){
    $('.vjs-menu').last().show();
    });
    $('.vjs-res-button.vjs-menu-button.vjs-control').on('mouseleave', function(){
    $('.vjs-menu').last().hide();
    });
    });

So in my opinion this thread can be closed as the problems originally reported now have been solved.

Thanks!

@carpasse
Copy link
Contributor

Hi guys

I have tested our video player on Android 4.3 default browser on a Galaxy nexus and a Galaxy s3 and the onClick function still gets called several times. It is no longer the same event type but now, 'tab' and 'click, events get raised one after the other. We have done our tests against version 4.11.4 and 4.12.5 of videoJs.

The only solution I could find was to debounce the the calls to onclick

I have done a plugin to fix this issue (es5 forEach polyfill required)

// This plugin fix the multiple click issue existing on android default browsers
// For more info please refer to https://github.com/videojs/video.js/issues/975

vjs.plugin('multiple-clicks-fix', function mobile(opts) {
  var player = this;

  player.ready(function () {
    walkChildrenTree(player, function (child) {
      if (isClickable(child)) {
        preventMultipleClicks(child);
      }
    });
  });

  /*** Local functions ***/
  function walkChildrenTree(component, handler) {
    component.children().forEach(function (child) {
      walkChildrenTree(child, handler);
      handler(child);
    });
  }

  function isClickable(component) {
    return typeof component.onClick === 'function';
  }

  function preventMultipleClicks(component) {
    var debouncedClick = debounce(component.onClick, 500, true);
    ['tap', 'click'].forEach(function(evt) {
      component.off(evt, component.onClick);
      component.on(evt, debouncedClick);
    });
  }

  /**
   *  Returns a function, that, as long as it continues to be invoked, will not be triggered.
   *  The function will be called after it stops being called for N milliseconds.
   *  If `immediate` is passed, trigger the function on the leading edge, instead of the trailing.
   */
  function debounce(func, wait, immediate) {
    var timeout;
    return function(evt) {
      var context = this;
      var args = arguments;
      var later = function() {
        timeout = null;
        if (!immediate){
          func.apply(context, args);
        }
      };
      var callNow = immediate && !timeout;
      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
      if (callNow){
        func.apply(context, args);
      }
    };
  }
});

I could do a PR to debounce the calls to onClick although, it seems a bit hacky.
What do you think??

@heff
Copy link
Member

heff commented Apr 11, 2015

@sangatpedas great to hear the issues have been fixed for you!

@carpasse that does feel a bit hacky, and could potentially lead to other bugs. If a touch event and a click event are both firing, it sounds like a preventDefault isn't getting called somewhere we need it to. Either that or Android ignores preventDefault and still fires both. Either way it'd be great to have a full understanding why that's happening before we patch it.

@carpasse
Copy link
Contributor

@heff I completely agree we need to investigate this better.

@gkatsev
Copy link
Member

gkatsev commented Nov 18, 2015

in v5, we default to native controls in the native android browser (#2499) which I believe closes this issue.
If there are still problems, we can reopen this issue.

@gkatsev gkatsev closed this as completed Nov 18, 2015
@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 27, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests