Android Multitouch - отслеживание нерегулярных пальцев - PullRequest
1 голос
/ 22 марта 2012

Я разработал простую мультитач-систему, которая отслеживает местоположение пальцев и их состояние на экране.Способ, которым разработана программа, когда два пальца опущены, им присваивается номер в зависимости от порядка размещения.Если палец один поднят, палец два по-прежнему называется пальцем два.

Этот код отлично работает время от времени.Это означает, что я буду запускать свое приложение в тестировании, и иногда мультитач работает каждый раз, а иногда использование более одного пальца приводит к полному отказу приложения.Это неправильно надежно.

Мне любопытно, если это аппаратная ошибка или что-то в том, как я обрабатываю сенсорный ввод.Все источники доступны ниже.

Спасибо за любую помощь, которую вы можете предложить!

- Натан Торнквист

РЕДАКТИРОВАТЬ: Я думаю, что проблема может быть сспособ, которым eventListeners зарегистрированы и незарегистрированные.Иногда приложение аварийно завершает работу и снова прекрасно работает, когда я снова открываю его.

РЕДАКТИРОВАТЬ 2: Проблема заключается в том, насколько нерегулярна программа.Иногда, когда я открываю его, он отлично отслеживает пальцы.Прижатый палец остается номером 1, второй - номером 2 и т. Д. Независимо от того, подняли ли вы палец 1 после размещения 2, номера остаются назначенными.В других случаях вы поместите два пальца, и какой палец 1, а какой 2 изменения.Приложение, похоже, теряет их след, и цифры переключаются, когда вы оставляете пальцы на экране.

РЕДАКТИРОВАТЬ3: Я пробовал «Усилители сенсорного экрана», чтобы попытаться, чтобы экран всегда реагировал правильно.Это не решило проблему.

РЕДАКТИРОВАТЬ4: После дополнительного тестирования это явно ошибка кода.Когда приложение запускается впервые, оно всегда работает отлично.После того, как устройство заблокировано (когда действие приостановлено), а затем разблокировано (когда действие возобновлено), мультитач перестает работать, и я получаю приложение, которое хорошо работает для одного касания и смущает мультитач.

MultitouchGameFixActivity.java

package com.nathantornquist.multitouchgame;

import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;

public class MultiTouchGameFixActivity extends Activity{
    /** Called when the activity is first created. */
    MainGamePanel viewPanel;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //Window state functions.
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

        //This works without declaring a viewPanel instance here.
        //The instance declaration is needed to pass the 
        //onPause and onResume commands though.
        viewPanel = new MainGamePanel(this);
        setContentView(viewPanel);
    }

    //Restarts the accelerometer after onPause
    protected void onResume() {
        super.onResume();
        viewPanel.resume(this);

    }

    //Standard Method run when the Application loses focus.
    //This runs the pause() function in the viewPanel so that
    //the accelerometer can be paused.
    protected void onPause() {
        super.onPause();   
        viewPanel.pause();

    }

    protected void onDestroy() {
        super.onDestroy();
        viewPanel.destroy();
    }
}

MainThread.java

package com.nathantornquist.multitouchgame;

import com.nathantornquist.multitouchgame.MainGamePanel;
import android.graphics.Canvas;
import android.view.SurfaceHolder;

public class MainThread extends Thread {

private SurfaceHolder surfaceHolder;
private MainGamePanel gamePanel;
private boolean running;
public boolean pleaseWait = true;
public void setRunning(boolean running) {
    this.running = running;
}

public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) {
    super();
    this.surfaceHolder = surfaceHolder;
    this.gamePanel = gamePanel;
}

@Override
public void run() 
{
    Canvas canvas;
    while (running) {
        if(!pleaseWait) {
            canvas = null;
            // try locking the canvas for exclusive pixel editing on the surface
            try {
                canvas = this.surfaceHolder.lockCanvas();
                synchronized (surfaceHolder) {
                    // update game state
                    this.gamePanel.update();

                    // draws the canvas on the panel
                    this.gamePanel.onDraw(canvas);
                }
            } finally {
                // in case of an exception the surface is not left in
                // an inconsistent state
                if (canvas != null) {
                    surfaceHolder.unlockCanvasAndPost(canvas);
                }
            }   // end finally            
        }
        else {
            synchronized (this) {
                try {
                    wait();
                } catch (Exception e) { }
            }
        }
    }
}
}

MainGamePanel.java

package com.nathantornquist.multitouchgame;

import android.R.string;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class MainGamePanel extends SurfaceView implements SensorEventListener, SurfaceHolder.Callback 
{
    //Variable Declarations.
    private MainThread thread;

    public int screenWidth;
    public int screenHeight;

    private SensorManager mSensorManager;
    private Sensor mAccelerometer;    

    Paint paint;
    public int fingerOneDown;
    public int fingerTwoDown;
    public int fingerThreeDown;
    public int fingerFourDown;
    public float fingerOneX;
    public float fingerOneY;
    public float fingerTwoX;
    public float fingerTwoY;
    public float fingerThreeX;
    public float fingerThreeY;
    public float fingerFourX;
    public float fingerFourY;

    public MainGamePanel(Context context)
    {
        super(context);

        getHolder().addCallback(this);

        thread = new MainThread(getHolder(),this);

        paint = new Paint();
        paint.setAntiAlias(true);

        Display display = ((Activity) context).getWindowManager().getDefaultDisplay(); 
        screenWidth = display.getWidth();
        screenHeight = display.getHeight();

        mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
        mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_FASTEST);

        fingerOneDown = 0;
        fingerTwoDown = 0;
        fingerThreeDown = 0;
        fingerFourDown = 0;
        fingerOneX = 0;
        fingerOneY = 0;
        fingerTwoX = 0;
        fingerTwoY = 0;
        fingerThreeX = 0;
        fingerThreeY = 0;
        fingerFourX = 0;
        fingerFourY = 0;

        setFocusable(true);

        thread.setRunning(true);
        thread.start();

    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        //continue the thread
        synchronized (thread) {
            thread.pleaseWait = false;
            thread.notifyAll();
        }

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        //pause the thread
        synchronized (thread) {
            thread.pleaseWait = true;
        }

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction() & MotionEvent.ACTION_MASK;
        int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;
        int pointerId = event.getPointerId(pointerIndex);
        switch (action) {
        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_POINTER_DOWN:
            Log.d("pointer id - down",Integer.toString(pointerId));
            if (pointerId == 0)
            {
                fingerOneDown = 1;
                fingerOneX = event.getX(pointerIndex);
                fingerOneY = event.getY(pointerIndex);
            }
            if (pointerId == 1)
            {
                fingerTwoDown = 1;
                fingerTwoX = event.getX(pointerIndex);
                fingerTwoY = event.getY(pointerIndex);
            }
            if(pointerId == 2)
            {
                fingerThreeDown = 1;
                fingerThreeX = event.getX(pointerIndex);
                fingerThreeY = event.getY(pointerIndex);
            }
            if(pointerId == 3)
            {
                fingerFourDown = 1;
                fingerFourX = event.getX(pointerIndex);
                fingerFourY = event.getY(pointerIndex);
            }
            break;

        case MotionEvent.ACTION_UP:          
        case MotionEvent.ACTION_POINTER_UP:
        case MotionEvent.ACTION_CANCEL:
            Log.d("pointer id - cancel",Integer.toString(pointerId));
            if (pointerId == 0)
            {
                fingerOneDown = 0;
                fingerOneX = event.getX(pointerIndex);
                fingerOneY = event.getY(pointerIndex);
            }
            if (pointerId == 1)
            {
                fingerTwoDown = 0;
                fingerTwoX = event.getX(pointerIndex);
                fingerTwoY = event.getY(pointerIndex);
            }
            if(pointerId == 2)
            {
                fingerThreeDown = 0;
                fingerThreeX = event.getX(pointerIndex);
                fingerThreeY = event.getY(pointerIndex);
            }
            if(pointerId == 3)
            {
                fingerFourDown = 0;
                fingerFourX = event.getX(pointerIndex);
                fingerFourY = event.getY(pointerIndex);
            }
            break;

        case MotionEvent.ACTION_MOVE:

            int pointerCount = event.getPointerCount();
            for(int i = 0; i < pointerCount; ++i)
            {
                pointerIndex = i;
                pointerId = event.getPointerId(pointerIndex);
                Log.d("pointer id - move",Integer.toString(pointerId));
                if(pointerId == 0)
                {
                    fingerOneDown = 1;
                    fingerOneX = event.getX(pointerIndex);
                    fingerOneY = event.getY(pointerIndex);
                }
                if(pointerId == 1)
                {
                    fingerTwoDown = 1;
                    fingerTwoX = event.getX(pointerIndex);
                    fingerTwoY = event.getY(pointerIndex);
                }
                if(pointerId == 2)
                {
                    fingerThreeDown = 1;
                    fingerThreeX = event.getX(pointerIndex);
                    fingerThreeY = event.getY(pointerIndex);
                }
                if(pointerId == 3)
                {
                    fingerFourDown = 1;
                    fingerFourX = event.getX(pointerIndex);
                    fingerFourY = event.getY(pointerIndex);
                }
            }
            break;
        }
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) 
    {        
        paint.setColor(Color.WHITE); 
        paint.setStyle(Style.FILL); 
        canvas.drawPaint(paint); 

        if (fingerOneDown == 1)
        {
            paint.setColor(Color.BLUE); 
            paint.setTextSize(20); 
            canvas.drawText("1", fingerOneX, fingerOneY - 30, paint); 
        }

        if (fingerTwoDown == 1)
        {
            paint.setColor(Color.RED); 
            paint.setTextSize(20); 
            canvas.drawText("2", fingerTwoX, fingerTwoY - 30, paint); 
        }
        if (fingerThreeDown == 1)
        {
            paint.setColor(Color.GREEN); 
            paint.setTextSize(20); 
            canvas.drawText("3", fingerThreeX, fingerThreeY - 30, paint); 
        }
        if (fingerFourDown == 1)
        {
            paint.setColor(Color.BLACK); 
            paint.setTextSize(20); 
            canvas.drawText("4", fingerFourX, fingerFourY - 30, paint); 
        }
    }

    public void update() {
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {        
    }

    @Override
    public void onSensorChanged(SensorEvent event) {

    }

    public void pause() {
        mSensorManager.unregisterListener(this);
    }

    public void resume(Context context) {
        mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_FASTEST);      
    }

    public void destroy() {
        thread.setRunning(false);

        if (thread != null)
        {
            Thread killThread = thread;
            thread = null;
            killThread.interrupt();
        }   

    }


}

Ответы [ 2 ]

0 голосов
/ 02 апреля 2012

Проблема решается отключением WidgetLocker.Это приложение иногда портит некоторые программы.Я также замечал проблемы в других приложениях, когда блокировал экран во время игры.

0 голосов
/ 29 марта 2012

Я выскажу некоторые идеи, хотя моим навыкам работы с Android немного не хватает ...

Как вы это тестируете?На реальном устройстве, я думаю?Можно ли это проверить на эмуляторе?Кажется, что это будет склонно к аппаратным проблемам.

Если есть сбой и экран теряет след пальцев даже на миллисекунду, не начнется ли с индексации пальцев?Если это так, то число пальцев будет довольно случайным, что приведет к проблемам, с которыми вы столкнулись.

Некоторые идеи:

  • Не отслеживайте указатель пальцев, просто ведите список пальцев и их относительное положение.Но я полагаю, что часть игры требует, чтобы вы держали указатель каждого пальца.
  • Журнал, если вы потеряли соединение с пальцем, покажет, является ли это isse.Я думаю, MotionEvent.ACTION_POINTER_UP - это событие, которое вы должны зарегистрировать.На самом деле, я бы добавил журнал для каждого возможного события, просто чтобы посмотреть, что происходит.
  • Добавить метод, который пытается определить, какой палец был помещен на экран, то есть он сравнивает текущее положение пальца с известными значениями предыдущих пальцев и, если он находится в пределах порога, предположим, что тот же палец,Вероятно, хотите добавить таймер, чтобы «забыть» предыдущие пальцы, а также.

Полагаю, вы просматривали пример мультитача в блоге разработчика Android , чтобы убедиться, что вы правильно используете API-интерфейсы?

Надеюсь, это может дать вамнекоторая помощь.

...