Нажмите на экран 5 раз в 3 секунды в android

Я разрабатываю киоск и теперь в админке. Чтобы перейти к администратору, пользователю нужно нажать экран 5 раз всего за 3 секунды или иначе, ничего не произойдет. Может ли кто-нибудь помочь мне с этой проблемой? Заранее спасибо!

Ответ 1

Пожалуйста, прочитайте комментарии в коде, это довольно просто

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;
  }

}

Ответ 2

Мое решение похоже на Андреса. Обратный отсчет начинается, когда вы поднимаете палец в первый раз, то есть, когда я считаю, что краны должны быть закончены. Это похоже на клики, щелчок происходит, когда вы отпускаете кнопку мыши. Через 3 секунды после первого подъема счетчик сбрасывается. Andres approch, с другой стороны, использует логику, основанную на том, чтобы перенести палец на экран. Он также использует дополнительный поток.

Моя логика - одна из многих возможных. Другим разумным подходом было бы обнаружить 5 последовательных отводов в течение 3 секунд в потоке кранов. Рассматривать:

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

Второй через шестой отвод включает в себя набор из пяти ответвлений менее чем за 3 секунды; в моем подходе это не будет обнаружено. Чтобы обнаружить это, вы можете использовать очередь FIFO фиксированного размера 5 и помнить последние 5 временных меток: эта последовательность увеличивается. Когда вы получаете новый ответ, вы проверяете, есть ли 1) произошло не менее 5 ответвлений, и 2) самая старая временная метка не старше, чем 3 секунды.

В любом случае, вернемся к первой логике, поместите этот код в 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);
    }
}

Примечание. Вероятно, вы захотите также сохранить состояние при изменении конфигурации. Как сказал бы математик, я допускаю это как упражнение для читателя

Ответ 3

Переопределите метод Activity onTouchEvent() чтобы получать события касания с экрана. Каждый раз, когда пользователь нажимает на экран приращение переменной и откладывает Runnable за 3 секунды, если это первый раз, когда вы касаетесь, если через 3 секунды события касания будут очищены, и ничего не произойдет. Поток проверяет, что число событий касания равно 5 или более, если они произошли до 3 секунд, переменная не очищается, и if(touchEvent >= 5) истинно. Я не проверял его! Но он полностью асинхронный :)

// 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();

Ответ 4

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){

        }
    }
}