Question

I am developing a kiosk and now in admin side. In order to go to the Admin, the user needs to tap the screen 5 times just in 3 seconds or else, nothing will happen.

Was it helpful?

Solution

Please read the comments in the code, it is quite straightforward

import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;

public class MainActivity extends Activity {

private int count = 0;
private long startMillis=0;

//detect any touch event in the screen (instead of an specific view)

@Override
public boolean onTouchEvent(MotionEvent event) {  

    int eventaction = event.getAction();
     if (eventaction == MotionEvent.ACTION_UP) {

     //get system current milliseconds
     long time= System.currentTimeMillis();


     //if it is the first time, or if it has been more than 3 seconds since the first tap ( so it is like a new try), we reset everything 
     if (startMillis==0 || (time-startMillis> 3000) ) {
         startMillis=time;
         count=1;
     }
     //it is not the first, and it has been  less than 3 seconds since the first
     else{ //  time-startMillis< 3000   
         count++;
     }

     if (count==5) {
        //do whatever you need
     }
     return true;    
    }
    return false;
  }

}

OTHER TIPS

My solution is similar to Andres's. The countdown starts when you lift the finger for the first time, that is, when I consider the tap to be finished. This is similar to clicks, a click occurs when you release the mouse button. After 3 seconds from the first lift, the counter is reset. Andres's approch, on the other side, uses logic based on placing the finger down onto the screen. It also uses an additional thread.

My logic is one of the many possible ones. Another reasonable approach would be to detect 5 consecutive taps within 3 seconds in a stream of taps. Consider:

tap1, 2000ms, tap2, 500ms, tap3, 550ms, tap4, 10ms, tap5, 10ms, tap6.

The second through the sixth tap encompasses a set of five taps in less than 3 seconds; in my approach this would not be detected. To detect this you can use a FIFO queue of fixed size 5 and remember the last 5 timestamps: this sequence is increasing. When you receive a new tap, you check whether 1) there are at least 5 taps occurred, and 2) the oldest timestamp is no older then 3 seconds old.

Anyway, back to the first logic, place this code in an Activity:

private int mCounter = 0;
private Handler mHandler = new Handler();

private Runnable mResetCounter = new Runnable() {
    @Override
    public void run() {
        mCounter = 0;
    }
};

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch(MotionEventCompat.getActionMasked(event)) {
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            if (mCounter == 0)
                mHandler.postDelayed(mResetCounter, 3000);

            mCounter++;

            if (mCounter == 5){
                mHandler.removeCallbacks(mResetCounter);
                mCounter = 0;
                Toast.makeText(this, "Five taps in three seconds", Toast.LENGTH_SHORT).show();
            }

            return false;

        default : 
            return super.onTouchEvent(event);
    }
}

Note: you probably want some state retention on configuration changes too. As a mathematician would say, I let that as an exercise to the reader

Override your Activity onTouchEvent() method to receive the touch events from the screen. Every time the user taps the screen increment a variable and postpone a Runnable in 3 seconds if it's the first time you touch, if 3 seconds passes the touch events will be cleared and nothing happens. A Thread checks for the touch events number to be 5 or more, if they happened before the 3 seconds the variable is not cleared and the if(touchEvent >= 5) condition is true. I haven't tested it! But it's completely asynchronous :)

// Touch events on screen
@Override
public boolean onTouchEvent(MotionEvent event) {
        // User pressed the screen
        if(event.getAction() == MotionEvent.ACTION_DOWN){
          if(touchEvent == 0) myView.post(mRunnable, 3000);  // Execute a Runnable in 3 seconds
          ++touchEvent;
        }
        return false;
}

Runnable mRunnable = new Runnable(){
        @Override
        public void run() {
           touchEvent = 0; // 3 seconds passed, clear touch events
        }
}

Thread mThread = new Thread(new Runnable(){
   @Override
   public void run(){
      if(touchEvent >= 5){
         // Touched 5 times in 3 seconds or less, CARE this is not UI Thread!
      }
   }
});
mThread.start();
private int touchSequenceCount = 0;
private Handler handlerTouchSequenceDetection;
private Runnable runnableTouchSequenceDetection;

public void setupTouchSequenceDetection(final View view){

    try {   

        view.setOnTouchListener(new View.OnTouchListener() {               
            public boolean onTouch(View v, MotionEvent event) {             

                int action = event.getAction();

                switch (action) {

                    case MotionEvent.ACTION_DOWN:

                        Log.d("setupTouchSequenceDetection", "touchCount: " + (touchSequenceCount+1));

                        if(touchSequenceCount == 0){

                            handlerTouchSequenceDetection.postDelayed(runnableTouchSequenceDetection, 2000);    

                        }else{

                            if(touchSequenceCount == 2){        

                                new AlertDialog.Builder(Activity_CheckIn_SelectLanguage.this)
                                .setMessage("warning message here")
                                .setCancelable(true)
                                .setPositiveButton("yes", new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog, int id) {

                                        resetTouchSequenceDetection(true);
                                    }
                                })
                                .setNegativeButton("no", new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog, int id) {

                                        resetTouchSequenceDetection(true);
                                    }
                                }).setOnCancelListener(new DialogInterface.OnCancelListener() {

                                    @Override
                                    public void onCancel(DialogInterface dialog) {

                                        resetTouchSequenceDetection(true);
                                    }
                                })
                                .show();
                            }

                        }

                        touchSequenceCount = touchSequenceCount + 1;

                    break;
                } 

                return false;
            }
        });


        handlerTouchSequenceDetection = new Handler(); 

        runnableTouchSequenceDetection = new Runnable() { 
             public void run() { 

                 Log.d("setupTouchSequenceDetection", "reset touchCount: " + (touchSequenceCount+1));

                 resetTouchSequenceDetection(false);
             } 
        };

    }
    catch(Exception ex){

        if(ex != null){

        }
    }
}

private void resetTouchSequenceDetection(boolean removeRunnable){

    try{

        if(removeRunnable){
            handlerTouchSequenceDetection.removeCallbacks(runnableTouchSequenceDetection);
        }

        touchSequenceCount = 0; 

    }
    catch(Exception ex){

        if(ex != null){

        }
    }
}

If you want to detect a touch on a view in KOTLIN

private var count = 0
private var startMillis: Long = 0
        
textView.setOnTouchListener { v, event ->
        if (event.action == MotionEvent.ACTION_UP) {
            val currentTime = System.currentTimeMillis()
            if (startMillis == 0L || currentTime - startMillis > 3000) {
                startMillis = currentTime
                count = 1
            } else {
                count++
            }
            if (count == 4) {
                
            }

            logd("count -- $count")
        }
        false
    }

In Java: https://stackoverflow.com/a/21104386/10784151

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top