Threaded View

  1. #1
    Sencha User
    Join Date
    Feb 2012
    Posts
    26
    Answers
    3
    Vote Rating
    1
    troels is on a distinguished road

      0  

    Default Answered: Multi touch and phonegap

    Answered: Multi touch and phonegap


    In ST 2.1 on Android 4, I'm seeing an issue when doing multi touch that causes my app to go into an error state, where no touch events are propagated to any components. i.e. the app completely freezes.

    On any container, it need not be scrolling or anything fancy, a drag with two fingers will cause this error. Note that the two fingers must hit the screen at the exact same time. After triggering the error, the browser will start throwing TypeErrors like:

    Uncaught TypeError: Cannot read property 'point' of undefined at file:///android_asset/www/resources/js/sencha-touch-all-debug.js:75290


    The culprit is the Ext.event.recognizer.Pinch class in the onTouchMove function that expects two points from the touch event, but only receives one. This crash seems to stop propagation throughout the rest of the recognizer classes.

    When in this faulty mode, I can see the PhoneGap is still sending touch events because the (appearently immortal) line

    WARN/webview(29014): Miss a drag as we are waiting for WebCore's response for touch down.

    still pops up when touching the screen.

    On containers that are scroll enabled, I have successfully undone this faulty state, by spamming multi touch events. At some point, ST realizes that a new multitouch event has begun and (im guessing) stops listening for updates to the one that crashed.

    A fix for this would be nice, but I can't launch a app with an error like this, so my question is:
    Where should I catch the TypeError and how to I cancel the touch event Ext.event.recognizer.Pinch still thinks is going on?

  2. The fix for this in Sencha 2.1 was more complicated than the first code i posted. It seems to happen on all Android 4 phones i've tried, whenever using multi touch. What actually happens is, when releasing a multi touch, one of the released points is never reported to the Sencha event processor. I expect this is an error in Android, like many others. The weird behavior is because Sencha thinks you're still holding one of your fingers on the screen.

    I solved it by first disabling all event processors i didn't need.
    Code:
    Ext.application({
        name: 'app',
        // disable all the below recognizers
        eventPublishers: {
            touchGesture: {
                recognizers: {
                    rotate: null,
                    doubleTap: null,
                    longPress: null,
                    swipe: null
                }
            }
        },
    
        ...
    
    })
    Then overriding the touch event processor so it's able to reset itself
    Code:
    Ext.define('app.overrides.TouchGesture', {
        override: 'Ext.event.publisher.TouchGesture',
    
    
        reset: function(e){
            if(Ext.os.is.Android4 && this.currentTouchesCount > 0){
                e.changedTouches = Ext.Object.getValues(this.currentTouches);
                this.onTouchEnd(e);
            }
        }
    });
    Then detect when the error occurs by overriding the Pinch detector
    Code:
    window.orgPinchEndMethod = Ext.event.recognizer.Pinch.prototype.end;
    Ext.define('app.overrides.Pinch', {
        override: 'Ext.event.recognizer.Pinch',
    
    
        end: function(e){
            var wasTracking = this.isTracking,
                result = window.orgPinchEndMethod.apply(this, arguments);
            if(wasTracking){
                this._resetDetection(e);
            }
            return result;
        },
    
    
        _resetDetection: function(e){
            // At this point, the pinch event is tracking meaning there should be two fingers on the screen.
            // There is only one active touch event tho, meaning that Android has not propagated the touch end event,
            // which would end the tracking. This now has to be done manually through this nasty hack
            var tg = Ext.event.Dispatcher.getInstance().getPublishers().touchGesture;
            setTimeout(function(){
                tg.reset(e);
            }, 0);
        }
    });
    Mind that this solution uses one touch to fix itself when the error occurs.