1

How to handle three presses on volume up button in my activity ?

    override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
        val action = event!!.action
        return when (val keyCode = event.keyCode) {

            //handle press on volume up button
            KeyEvent.KEYCODE_VOLUME_UP -> {
                if (action == KeyEvent.ACTION_UP) {
                    
                }
                true
            }
 else -> super.dispatchKeyEvent(event)
        }
    }
  • The logic can be same as [This](https://stackoverflow.com/a/21764444/4168607) you save the last clicked time and just validate the next click withing the interval .. – ADM Mar 21 '22 at 12:23

1 Answers1

1

You could encapsulate the handling of multi-taps in a helper class like this. This class accepts each tap of the button when you call submitTap(), and if the specified number of taps happen within a certain amount of time (withinMillis), then it fires the onMultiTap callback. If it has been too long since the first of the taps it has been counting, it resets its time and counts the latest tap as the first of a new count.

class MultiTapHandler(
    val multiTapCount: Int,
    val withinMillis: Long,
    var onMultiTap: () -> Unit
) {
    init {
        require(multiTapCount > 1) { "Must have multiTapCount of at least 2." }
    }

    private var firstInputTime = 0L
    private var count = 0

    fun submitTap() {
        val time = System.currentTimeMillis()
        when {
            count == 0 || time - firstInputTime > withinMillis -> {
                count = 1
                firstInputTime = time
            }
            ++count == multiTapCount -> {
                count = 0
                onMultiTap()
            }
        }
    }
}

So to use it in your code, where you want to do something when there is a triple-tap of the volume button, you would store it in a property with a multiTapCount of 3. You can experiment with values of withinMillis to find what feels right.

private val tripleVolumeUpHandler = MultiTapHandler(3, 500L) {
    Log.d(TAG, "Just got triple tap on volume up button!")
}

override fun dispatchKeyEvent(event: KeyEvent): Boolean {
    val action = event.action
    return when (val keyCode = event.keyCode) {
        KeyEvent.KEYCODE_VOLUME_UP -> {
            if (action == KeyEvent.ACTION_UP) {
                tripleVolumeUpHandler.submitTap()
            }
            true
        }
        else -> super.dispatchKeyEvent(event)
    }
}

Edit: If you want to handle single, double, and triple taps of the button, you can create a second instance like this:

private val doubleVolumeUpHandler = MultiTapHandler(2, 250L) {
    Log.d(TAG, "Just got double tap on volume up button!")
}

private val tripleVolumeUpHandler = MultiTapHandler(3, 500L) {
    Log.d(TAG, "Just got triple tap on volume up button!")
}

override fun dispatchKeyEvent(event: KeyEvent): Boolean {
    val action = event.action
    return when (val keyCode = event.keyCode) {
        KeyEvent.KEYCODE_VOLUME_UP -> {
            if (action == KeyEvent.ACTION_UP) {
                doSingleTapAction()
                doubleVolumeUpHandler.submitTap()
                tripleVolumeUpHandler.submitTap()
            }
            true
        }
        else -> super.dispatchKeyEvent(event)
    }
}
Tenfour04
  • 83,111
  • 11
  • 94
  • 154
  • Thanks for your answer Tenfour04, but I do what you answer but there is nothing shows in logcat ! – Ayman Mazra'awi Mar 21 '22 at 13:14
  • I tested it and it's working in my project. You probably need to set the `withinMillis` to at least 500 to be able to triple-tap fast enough. You might also have a problem with your key dispatching. Try logging from within the same `if` block you're calling `submitTap` from to make sure it's firing when you expect. – Tenfour04 Mar 21 '22 at 13:43
  • Last question, There is any way to handle single, double and three press in same dispatchKeyEvent function ? – Ayman Mazra'awi Mar 23 '22 at 09:33
  • If you wanted to do them all for the same key and skip firing a single or double click callback when there’s a triple click, then you have to also set a timer after each click, and fire a different callback if the next click doesn’t arrive in time. So the logic of the helper class would be more complex and there will be a slight delay when you single or double click before the action happens. But if you just want it to always allow clicks or double clicks to fire and also be part of a triple click, then you could just add two instances of this class and use both. – Tenfour04 Mar 23 '22 at 10:28
  • Can you briefly explain more please, if you don't mind ? – Ayman Mazra'awi Mar 23 '22 at 11:28
  • Which behavior do you want? If a user triple taps quickly, should all three events fire, or only triple tap event? – Tenfour04 Mar 23 '22 at 11:33
  • I want when user press two times do thing and when press triple do another thing separately. – Ayman Mazra'awi Mar 23 '22 at 11:37
  • Then you just need to add two instances of the above helper class and submit taps to both of them. And directly do the event that happens on each single click. – Tenfour04 Mar 23 '22 at 11:38
  • I have already thought about that but I don't get how to do this in dispatchKeyEvent function – Ayman Mazra'awi Mar 23 '22 at 11:43
  • I added code to demonstrate it. – Tenfour04 Mar 23 '22 at 12:20
  • I tried this but when I press triple time ... doubleVolumeUpHandler.submitTap() also appear in Logcat, also when I use double press single press appear. – Ayman Mazra'awi Mar 23 '22 at 12:42
  • That's what I was asking if it was the behavior you wanted. If you want to prevent a single or double tap event when there's a triple tap, that's a lot more complicated. You need to add timers like I mentioned. I don't have time to go into a detailed solution on that right now. – Tenfour04 Mar 23 '22 at 13:59