Mapsui: [Forms.Droid] No SingleTap-, DoubleTap- or LongTap event on Samsung Galaxy devices

Created on 17 Feb 2019  ·  49Comments  ·  Source: Mapsui/Mapsui

All devices with the same modifications as Samsung did for their Galaxy devices seems to have problems with the events - they never happen. I'm not entirly sure yet what causes this issue but I was able to have the same issue with the Sample projects from the repo but not with apps using Mapsui 1.x.

bug 🐛

All 49 comments

The Forms sample projects? Or all sample projects for Android?

@charlenni Did only tested with the forms sample yet. I can test with the normal one when I'm home again (if I don't forget it).

I'm seeing the same thing on the UWP Forms Sample projects. Ran the PinSample as a quick test on UWP and it didn't register the map click. This issue seems to be that Mapsui thinks a Feature is selected on every click so its not firing the MapClicked event. This was working in Beta 16, haven't tried Beta 17.

Sample project works fine in Beta 17, so its something that's changed since then. I'll try to take a look around, but I'm new to the code base. The Tapped events appear to be working on the non-Forms sample projects.

I am having a similar issue on Samsung devices using Xamarin.Forms.
Basically, tap is recognized as a 1px move gesture. If you tap lightly and very fast than Tap event fires.

I have experienced it on beta 15 and 18.

So, now I had time to check this.

The problem is the change here. Now the raster map layer is a map info layer. With this, GetMapInfo returns always a feature (a raster feature) and calls than Info instead of MapClicked. So, if you want to have a MapClicked instead of a Info event, you should set IsMapInfoLayer of raster map layer to false.

if you add a
mapControl.Map.Layers[0].IsMapInfoLayer = false;
in function Setup() of PinSample.cs, than all works again as you expect.

@pauldendulk Any reason, why you changed this?

@charlenni I have the same problem in my app (but only on Samsung Galaxy devices - well maybe on others too but those are the ones I notice the issue, tested Pixel, Xiaomi and Asus devices which all work with the same binary) and the IsMapInfoLayer of the tile layer is already false. It always move for about a pixel if I try to tap on a icon. The very same binary works on other Android devices and if I compile it for iOS it works as well.

Edit: Only the report from @lumberjack4 refers to the change in the sample project. The reported issue, and the one @Feroks mentioned, is a different. I think it has something todo with the Samsung Experience modifications on Android but this issue did not happen with Mapsui 1.x. So far it works on any tested device and simulator as expected except on the ones with the Samsung Experience UI.

Ok, than I try it with a Samsung Galaxy A5 and hope, that I could find the problem.

@charlenni I am not sure this is Mapsui issue. I have subscribed to Touch event on MapControl, which is raised by SKGLView.

It raises sequence of events when I simply tap. ActionTypes of the events "Pressed", "Moved", "Released", instead of just simply “Pressed”.

@feroks This is right. You could replace “Pressed” with down und “Released” with up. MapControl for Forms than create from this events your tap events.

It would be interesting, if you get for a normal tap a move event. You shouldn’t normally get one. Could you check this please?

Sorry. The MapInfoLayer = true is my mistake. Testing code for the perpormance issue. I will release a fix today.

I dont see how this mistake could cause issues specifically for samsung.

@pauldendulk The problem here also happens when the tile layer "IsMapInfoLayer" is false.

@charlenni I think for other devices you do not get "Move" event. It is just “Pressed” and “Released”. I can check it out tomorrow.

As for now, I made a dirty hack. I inherit from MapView and subscribe to TouchStart and TouchEnd events. If timespan between them is less than 100ms I invoke HandleTap method manually. Sadly, I had to use reflection, because it is a private method. You still get that strange 1px movement, when you tap on Samsung devices, but at least Tap is processed.

I guess I can do it in MapControl instead, as you have suggested.

@charlenni If you add mapControl.Map.Layers[0].IsMapInfoLayer = false; the tap event works; however, any interactive widgets on the map no longer work. You can see this with the ZoomInOutWidget located at the bottom right of the map in the samples.

@lumberjack4 your response still only affects the sample and not the actual problem here. UWP is not affected by the issue here and neither is iOS or most part of Android devices. This problem seems to be a problem with Samsung Experience UI in combination with Mapsui 2.x.

It seems, that I have to allow a small movement between pressed and released.

Properly reading through this thread for the first time now. Here are some of my thoughts.

  • The mapControl.Map.Layers[0].IsMapInfoLayer = false issue is related but only part of the problem.
  • When dragging the map there should never be a MapInfo event. When the map is moved a certain distance (in device pixels) there should be no MapInfo. A tiny move should be allowed because there is always some movement when you are trying to touch a feature. It is supposed to work this way in the native MapControls.
  • Another change I made right before the release is that the MapInfo event only collects items for a small envelope, this is necessary for performance and the correct thing to do, but it might have unknown side effects on other logic.
  • The fact that is does not work on Samsung but it does on other Android devices is very peculiar and is an indication it is a bug somewhere else. Still we need to find out where this bug originates and try to find a workaround.

@charlenni The XF MapView keeps the _touches in memory. Why is this? Is it a workaround for a limitation of XF? Does it provide added functionality? Is it related to gestures? Would it be possible to use the same kind of touch logic as in the natives MapControls?

@pauldendulk I keep in this array the IDs for each finger that touches the screen. And yes, the native MapControls do the work for you. For the Forms MapControl I do this by my own.

Normally the tap gesture has no movement. That works perfect for all devices other than Samsung’s 😉 Samsung seems to has always a move even if it is only one pixel.

Ok, I now see the problem on Samsungs.

On Samsungs there isn't a combination, but a + combination. It looks like
Pressed at {X=588, Y=828} Moved to {X=587, Y=828} Released at {X=587, Y=828}
but could also like this
Pressed at {X=605, Y=976} Moved to {X=601,2876, Y=975} Moved to {X=598,5, Y=975} Moved to {X=596,5, Y=975} Moved to {X=595,5059, Y=975} Moved to {X=597, Y=975} Released at {X=597, Y=975}
Both are normal taps. It seems, that Samsung displays (or code) is very sensitiv to touches.

So what to do in this case? Say a tap is a tap, when it is not further away than 1 pixel? Or 10 pixel? Or a user defined amount of pixels? Or any other algorithem to detect, if this is a tap?

I made a PR with a check for a 2 pixel distance of touch start and touch end in eaqch direction with #605.

On any touch device such an arbitray descision is made. They have to choose some number of pixels. We need to find out what this threshold is on Android and iOS. Might even be a system parameter.

@pauldendulk This is a very strange problem. Normally it is possible to make a touch start - touch end combination without any move on all platforms. Only Samsung has problems with this. If you try this there, you get touch move events between start and end and see the map really moving.

@charlenni I think we can conclude that it is a bug in Samsung but we need to find a workaround.

So on Samsung there is an actual touch start and touch end event as well? Like on the other platforms? With move events in between? If so, could we perhaps find another way to detect if we are between start and end and ignore move events in between?

  • Can we request the touch down state from the arguments?
  • Or the OS?
  • Or could we keep track of the state ourselves? So after a touch start we set a boolean to true and ignore further touches until touch end is called and then set the boolean to false?

I could not find time to look at the actual code and behavior so some of my suggestions might be off the mark. Sorry for that.

@pauldendulk I assume, that Samsung display are more reactive than others.

I rise up to now tap events, if the touch doesn't move between touch start and touch end and the time between touch start and touch end is short. For Samsung this seem not to work. They move between touch start and touch end in 90% of the cases. Because if this I added in #605 a check, if the location moves only a small distance (2 pixels in each direction). This should avoid the problem in the most cases.

@pauldendulk Btw. I haven't a possibility to check, on which platform the code is running. For this I need platform special things from a renderer, which I haven't.

@charlenni Ah, so you think it could be a hardware difference, might be. I will release beta 20 with your changes.

@pauldendulk Could be hardware or software (like @Sebastian1989101) suggested.

You could find something about that at stackoverflow. There the author get the same problem with a Samsung. Perhaps all other Android and iOS implementations do allready a check in touch move, if the new location is more than x pixel away from the old location and only than raise a touch move event, where as Samsung always raise an touch move event.

With the last said, should the correction take place in touch move event (only if the location changes more than x pixel a drag is started) or should it take place in touch end event (only if the location changes less than x pixel a tap is fired)?

@charlenni It might also depend on the hardware revision or software version. Also Samsung is pretty popular for using different CPU's in the same device (for example on the Galaxy S8: Europa: Samsung Exynos 8895; China/USA: Qualcomm Snapdragon 835) and because of a different CPU there might also be a difference in the software/firmware.

I've just pushed a version with beta 20 to the public TF and to the internal Android testing. So far, single tap works about 80% of the time now on Samsung devices. But double tap is still hard to pull of and long tap is still not possible (I guess it still moves too much for it?).

@Sebastian1989101 I could increase the amount of pixels that are tolerated when touching.

Looked further and found the original source code, where this is handled in Android. See here in line 617. Android uses a configurable paramater, which could be found in this part of the source code at line 151. The question is, if this is a parameter that the user could define in their settings or if this is a parameter that Samsung defines for you.

Any suggestion, what to do? Should I set the slop distance freom 2 to 8? Should I add a property, so that each user could determin this by her/his own? Should the map move, even if we are not sure, that this gesture is a move, but a tap?

@charlenni What did Mapsui 1.x used for this? How was it handled there for these kind of devices? Because it works with Mapsui 1.x so maybe there is some useful information for this?

Mapsui 1.x uses the native gestures of the platforms. For e.g. Android it uses the code I send you. Could be slightly different for Samsungs, but not so much.

So this part of code is very new for Mapsui ;)

@charlenni Thanks for getting to the bottom of this! The Android source code you point to gets the touchSlop from the ViewConfiguration, which can be created within an Android view like in this Kotlin code over here:

https://developer.android.com/training/gestures/viewgroup#kotlin

In C# it looks like this:
c# var touchSlop = ViewConfiguration.Get(Context).ScaledTouchSlop;
Unfortunately we can not use it in Xamarin Forms. I don't expect a solution for this in Xamarin.Forms. We could try to solve it with some kind of interface injection, but then we have to figure it out for UWP and iOS as well. Too much work for now. Lets just use the default value. Which is .... uh ... 8? @charlenni You suggested 8 as slob. Why was that?

When I request ScaledTouchSlop in my android app it returns 24. Which is quite a big distance I would say. Perhaps it is multiplied with the PixelDensity and it's actual dp distance is 8.

Should the map move, even if we are not sure, that this gesture is a move, but a tap?

I think the map should move right away. Otherwise the map seem unresponsive on every drag. So when the touch is within the slob distance the map will drag and tap.

@pauldendulk Sorry, see, that I provided the wrong link to the code of ViewConfiguration.java. Here is the correct one, where you could find in line 151 the part, where the default values are set. And yes, the default is 8 dips, which could be on your display 24 px.

Ah, good. So I would say we understand everything. Let's just choose 8 for now. In the future we might want to use some platform independent wrapper over ViewConfiguration (and it's alternatives in iOS and UWP). This could be the kind of solution used in Xamarin.Essentials. Perhaps it already has (or get) something like that. It could even become part of XF itself. I think for us this will not be necessary soon.

@pauldendulk Should I create a new PR for this or do you change this when creating the next beta?

I will change it. Thanks for helping out.

@charlenni btw, you can also get a url pointing directly to a line number. It is possible in github as well. If you click the number in front of the line you get the deep linked version.

https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/ViewConfiguration.java#162

@charlenni I changed the margin to 8. Is there a way to test this?

@pauldendulk I assume, that @Sebastian1989101 has the best test case.

Ok. Beta 22 has the changes.

@charlenni @pauldendulk Here is a public beta build with the Mapsui beta 22 included. So far no reports about any map problems: https://play.google.com/apps/testing/com.SoftwareNotion.TLoZCompanion

Also the test cloud tests on Microsoft AppCenter runs with a good response on Samsung devices now.

Thank you @Sebastian1989101 for the response. That are very good news.

Do you see on Android while moving around on the map and zooming white lines, as described in #622?

@charlenni Nothing I have noticed so far and also no reports for this kind of issue. Maybe it is device specific too?

@Sebastian1989101 Thanks for the test analysis.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

YordanYanakiev picture YordanYanakiev  ·  6Comments

kisslori picture kisslori  ·  8Comments

lukaszpitulski picture lukaszpitulski  ·  8Comments

Kayumiy picture Kayumiy  ·  9Comments

charlenni picture charlenni  ·  3Comments