Log all of an Activity’s touch events?

Asked

Viewed 97 times

3

I need to log all the actions of a user in an Activity:

For example:

click on R.id.btn_ok view

longclick on R.id.listview-item

2 answers

3


I found the challenge interesting so I made two small classes, Toucheventlogger to log "Touch Events" and Gestureeventlogger for the "Gesture Events".
Both inherit from Motioneventlogger.

Motioneventlogger.java

public abstract class MotionEventLogger {

    public interface Logger{
        public void log(String text);
    }

    protected Logger logger;
    private String TAG = MotionEventLogger.class.getSimpleName();;

    public MotionEventLogger(Logger logger) {

        if(logger == null){
            this.logger = new DefaultLogger(TAG);
        }else{
            this.logger = logger;
        }

    }

    abstract void log(MotionEvent event);

    protected static class DefaultLogger implements Logger{

        final String TAG;
        public DefaultLogger(String TAG) {
            this.TAG = TAG;
        }

        @Override
        public void log(String text) {

            Log.i(TAG, text);
        }

    }

    //Fonte: http://stackoverflow.com/a/14985355/2556111
    protected View findViewAtPosition(View parent, int x, int y) {
        if (parent instanceof ViewGroup) {
            ViewGroup viewGroup = (ViewGroup)parent;
            for (int i=0; i<viewGroup.getChildCount(); i++) {
                View child = viewGroup.getChildAt(i);
                View viewAtPosition = findViewAtPosition(child, x, y);
                if (viewAtPosition != null) {
                    return viewAtPosition;
                }
            }
            return parent;// null;
        } else {
            Rect rect = new Rect();
            parent.getGlobalVisibleRect(rect);
            if (rect.contains(x, y)) {
                return parent;
            } else {
                return null;
            }
        }
    }

    protected String getViewIdText(View viewTouched) {
        String viewIdText;
        if(viewTouched.getId() == View.NO_ID){
            viewIdText = viewTouched.getClass().getSimpleName() + " sem id";
        }else{
            viewIdText = viewTouched.getResources().getResourceEntryName(viewTouched.getId());
        }
        return viewIdText;
    }   

}

Toucheventlogger.java

public class TouchEventLogger extends MotionEventLogger {

    private ViewGroup contentView;
    private int touchSlop;
    private boolean canLogMove = false;


    public TouchEventLogger(ViewGroup viewGroup, Logger logger) {
        super(logger);

        contentView = viewGroup;
        touchSlop = getTouchSlop(viewGroup);
    }

    public TouchEventLogger(ViewGroup viewGroup) {
        this(viewGroup, null);

    }

    public TouchEventLogger(Activity activity, Logger loger) {
        super(loger);

        contentView = (ViewGroup)((ViewGroup)activity.findViewById(android.R.id.content)).getChildAt(0);
        touchSlop = getTouchSlop(contentView);
    }

    public TouchEventLogger(Activity activity) {
        this(activity, null);
    }

    @Override
    public void log(MotionEvent event){

        float initialX = 0, initialY = 0;
        int action = event.getActionMasked();
        int eventX = (int) event.getX();
        int eventY = (int) event.getY();

        View viewTouched= findViewAtPosition(contentView, eventX, eventY);
        if(viewTouched == null)return;

        String viewIdText = getViewIdText(viewTouched);

        switch (action) {

            case MotionEvent.ACTION_DOWN:
                initialX = eventX;
                initialY = eventY;
                canLogMove = true;
                logger.log(viewIdText + " Action DOWN");
                break;

            case MotionEvent.ACTION_MOVE:

                float xDiff = initialX - eventX;
                float yDiff = initialY - eventY;

                if(canLogMove && (Math.abs(xDiff) > touchSlop || Math.abs(yDiff) > touchSlop)) {
                    logger.log(viewIdText + " Action Move");
                    canLogMove = false;
                }
                 break;

            case MotionEvent.ACTION_UP:

                logger.log(viewIdText + " Action UP");
                break;

            case MotionEvent.ACTION_CANCEL:
                logger.log(viewIdText + " Action CANCEL");
                break;

            case MotionEvent.ACTION_OUTSIDE:
                logger.log(viewIdText + " Movement occurred outside bounds of current screen element");
                break;
        }
    }

    private int getTouchSlop(View view){
        ViewConfiguration vc = ViewConfiguration.get(view.getContext());
        return vc.getScaledTouchSlop();

    }
}

Gestureeventlogger.java

public class GestureEventLogger extends MotionEventLogger implements
        GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener{

    private GestureDetector gestureDetector;
    private String viewIdText;
    protected ViewGroup contentView;

    public GestureEventLogger(Activity activity, Logger loger) {
        super(loger);

        contentView = (ViewGroup)((ViewGroup)activity.findViewById(android.R.id.content)).getChildAt(0);
        setDetector(activity);
    }

    public GestureEventLogger(Activity activity) {
        this(activity, (Logger)null);
    }

    public GestureEventLogger(Context context, ViewGroup viewGroup, Logger logger) {
        super(logger);
        contentView = viewGroup;
        setDetector(context);
    }

    public GestureEventLogger(Context context, ViewGroup viewGroup) {
        this(context, viewGroup, null);
        setDetector(context);
    }


    @Override
    public void log(MotionEvent event) {

        View viewTouched= findViewAtPosition(contentView, (int)event.getX(), (int)event.getY());
        if(viewTouched != null){
            viewIdText = getViewIdText(viewTouched);
            gestureDetector.onTouchEvent(event);
        }
    }

    @Override
    public boolean onDoubleTap(MotionEvent arg0) {
        logger.log(viewIdText + " DoubleTap");
        return true;
    }

    @Override
    public boolean onDoubleTapEvent(MotionEvent arg0) {
        //logger.log(viewIdText + " DoubleTapEvent");
        return false;
    }

    @Override
    public boolean onSingleTapConfirmed(MotionEvent arg0) {
        logger.log(viewIdText + " SingleTap");
        return true;
    }

    @Override
    public boolean onDown(MotionEvent arg0) {
        //logger.log(viewIdText + " Down");
        return false;
    }

    @Override
    public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2,
            float arg3) {
        logger.log(viewIdText + " Fling");
        return true;
    }

    @Override
    public void onLongPress(MotionEvent arg0) {
        logger.log(viewIdText + " LongPress");
    }

    @Override
    public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2,
            float arg3) {
        //logger.log(viewIdText + " Scroll");
        return false;
    }

    @Override
    public void onShowPress(MotionEvent arg0) {
        //logger.log(viewIdText + " ShowPress");
    }

    @Override
    public boolean onSingleTapUp(MotionEvent arg0) {
        //logger.log(viewIdText + " SingleTapUp");
        return false;
    }

    private void setDetector(Context context) {
        gestureDetector = new GestureDetector(context, this);
        gestureDetector.setOnDoubleTapListener(this);
    }

}

Use them as follows:

Declare a private variable to Activity:

private MotionEventLogger eventLogger;

In the method onCreate() create an instance of Toucheventlogger or of Gestureeventlogger:

eventLogger = new TouchEventLogger(this);
//ou
//eventLogger = new GestureEventLogger(this);

Do the override of the method dispatchTouchEvent() and call eventLogger.log(event);:

@Override
public boolean dispatchTouchEvent(MotionEvent event) {

    eventLogger.log(event);
    return super.dispatchTouchEvent(event);
}

By default the log is done in Logcat. You can make your own logger, make him implement the interface MotionEventLogger.Logger and pass it on the constructor.

  • Perfect.. was only missing when the element is inflated in Activity. And when widgets are created in Runtime, some hint?

  • I believe that such situations will be considered if the Toucheventlogger is created after they happened. I will edit the answer as I have been making some changes and also made a class to log Gestures

  • Note that in addition to the constructor that receives a Activity there is also one who receives a Viewgroup.

  • perfect, so I create a logger for these situations tbm, thank you very much.

  • The Gestureeventlogger.java does what it asks in the question: identifies the click and the longClick.

0

        onCreate(){
    setContentView(R.layout.activity_main);

    View view = findViewById(R.id.main); 
    view.setOnTouchListener(new View.OnTouchListener() {

   @Override
  public boolean onTouch(View view,MotionEvent event) {
      return true;   }
                      });
  • didn’t work..

  • edited, try it this way.

  • I took the root view from Activity... but it doesn’t take the events.. getWindow().getDecorView().setOnTouchListener

Browser other questions tagged

You are not signed in. Login or sign up in order to post.