I'm trying to use JavaScript and jQuery to capture touch events. But I'm seeing some very odd behavior in the Web browser on Android 2.3.2: whenever I tap the screen, and then quickly tap somewhere else on the screen, the browser:
The orange border seems to be just a related symptom of the same underlying problem, so I'm not too worried about it -- it's actually convenient for being able to tell when the browser is screwing things up. What I really want to know is, how can I consistently get the right touch events for two quick taps? I believe that when that problem is solved, the orange border will go away as well.
What follows are all the painful details I've worked out so far.
Here's a page that shows the problem and displays lots of diagnostic information about the details and timing of each event that's received. You're sure to get the orange flash / bad events if you tap inside the blue rectangle, then quickly tap inside the black rectangle.
My jQuery code is pretty standard. The log
function's implementation isn't important; the problem is that the browser doesn't call it when it should.
el = $('#battle');
el.on('touchstart', function(event) {
log(event);
return event.preventDefault();
});
el.on('touchend', function(event) {
return log(event);
});
el.on('touchcancel', function(event) {
return log(event);
});
el.mousedown(function(event) {
log(event);
return event.preventDefault();
});
return el.mouseup(function(event) {
return log(event);
});
More details on the phenomena I described initially:
Orange border and highlight: This is the same orange border and highlight that the browser draws around a hyperlink when you click it. But there are no hyperlinks on the page, and the browser draws this orange border around the whole screen -- or more specifically, around the outer <div id="battle">
that I'm hooking events on via jQuery.
Wrong events: In my touchstart
event handler, I'm calling event.preventDefault()
, to tell the browser not to scroll, not to synthesize mouse events, etc. Therefore, I expect to get only touchstart
and touchend
events. And I do, for the first tap. But instead of touchstart
/touchend
for the second tap, I get all number of combinations of touch events, synthesized mouse events, and the occasional touchcancel
for the second tap, or even repeated events for the first tap. Details below.
This behavior also only occurs in very particular circumstances:
touchstart
).touchstart
).mousedown
and mouseup
, the orange rectangles no longer appear. However, the touch events are sometimes still garbled.As far as what I mean by the events being garbled, here's what I see. When I write "1:", that means the events are for the first tap's coordinates; "2:" means the second tap's coordinates. I saw the following patterns of events (percentages indicate how many times each one came up after 100 trials):
Some combinations of events seem to come up more often depending on how quickly I tap, but I haven't quite nailed down the pattern. (Two quick, crisp taps seem more likely to come in under the second item above, whereas a more rapid-fire approach with less emphasis on crispness seems more likely to be the first item. But I haven't identified specific timing numbers that lead to each.) Similarly, the "short delays" indicated above can be anywhere from ~150ms to ~400ms; I haven't reverse-engineered the whole pattern there either.
If I don't hook mousedown
and mouseup
, the distribution is roughly this:
So if I don't hook the mouse events, it works a third of the time; and if I was willing to pretend that touchcancel
meant the same thing as touchend
, I could get that up to 75% of the time. But that's still pretty sucky.
Alternatives I've already tried:
vmousedown
and vmouseup
events, but they aren't always triggered for the second tap, I suspect because of this same underlying event weirdness.preventDefault
on the touchstart
usually achieves that (though occasionally the second tap is actually able to scroll the screen despite my preventDefault
... another reason I want to solve this whole event mess).Can anyone suggest a way to change my HTML, my event handlers, or anything else in order to reliably get touch events for two quick taps in succession?
Having tried to develop multi-touch HTML5 games in the Android browser (and trying them in other Android compatible browsers too), I think Android 2.x's browser simply does not properly support touch input. For starters, it doesn't support multi-touch which makes some kinds of game unplayable. (Obviously the phone supports multi-touch because you can pinch zoom etc., but the browser doesn't.) Then there are lots of problems with latency, touches 'sticking' and so on. I vaguely remember reading something about the phone's drivers for touch inputs not really working with true multitouch (i.e. it can detect either single touch or pinch zooms and that's it), but I don't have any references to back that up...
Apparently Android 4 (Ice Cream Sandwich) fixes it. So you might just have to wait for Android 4, which should be out soon anyway, and try again. Beyond that, Google have announced they're planning to replace the Android Browser with a mobile version of Chrome in future, so hopefully at least by then our browser touch-input woes will be over.
This is a theory: Wasn't able to test extensively
According to the init function in the soruce code of a webview, the statement setFocusable(true)
is always called on a webview during its initialisation.
When I tried to make the view not focusable anymore using setFocusable(false)
the error did not happen again. It seems the orange box does not appear. I was testing this on a small samsung phone running os 2.3.4. What I am sure of is that this orange box did not re appear.
In case this turns out to be true, it is highly likely that we can solve this without our own webview. What makes things more complicated is if setting the focusable property to false triggers other problems.
Finally, I do not think we can control this property from javascript (or can we?). Maybe You can declare that a specific control or the whole document is not an input or something like that? I am only extrapolating so bare that this may be false.
Edit: Regarding your comment on your question I just created a blank application with only a Webview that loads your url after setting its focusable property to false. Please, if you have more resources to test it, I will upload it for you to try it. Here is the application
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With