Inside of the onReceive(Content context, Intent intent) method of my public class MediaButtonIntentReceiver extends BroadcastReceiver I need to count the number of headset button clicks (single, double, triple), which is denoted by KeyEvent.ACTION_DOWN of the ACTION_MEDIA_BUTTON.
What I have almost works, but my current algorithm sucks and is unreliable after a few times. Basically every successive ACTION_DOWN (hit within a certain number of milliseconds to the previous ACTION_DOWN) I do numClicks++. But also I need to see when the user is done pressing, so after each event I start a CountDownTimer, and if by the time it runs out there are no new clicks, then I’m done and now know the number of clicks.
The problems I’m running into are as follows: for one, the button itself seems noisy – if I press it too fast I usually miss a click. Two, after a few trials when the app it loaded, it starts getting random and I’m assuming that there are multiple CountDownTimer threads (is that the right word?) still running which screws my stuff up.
Anyways here’s the main code snippet:
//note: thisClickTime uses System.currentTimeMillis()
if (action == KeyEvent.ACTION_UP) {
if (isDown == true) {
if (numClicks == 0 && lastClickTime == 0) {
//we have a new click
numClicks++;
lastClickTime = thisClickTime; //update the click time
isDown = false;
elapsedTime = thisClickTime - lastClickTime;
} else if (thisClickTime - lastClickTime < clickDelay) { //&& thisClickTime - lastClickTime > 10
numClicks++;
lastClickTime = thisClickTime;
isDown = false;
}
final int oldNumClicks = numClicks;
final CountDownTimer checkIfDone = new CountDownTimer(clickDelay, 10) {
public void onTick(long millisUntilFinished) {
if (oldNumClicks != numClicks) {
cancel();
}
}
public void onFinish() { //code that executes when counter is done
if (oldNumClicks == numClicks) {
//if user doesn't click anymore in time clickDelay + X milliseconds, then it's done
Toast.makeText(context, "Number of clicks: " + Integer.toString(numClicks), Toast.LENGTH_SHORT).show();
//reset state variables
numClicks = 0;
lastClickTime = 0;
}
}
}.start();
} else {
//?
}
}
For reference, I’ve been looking around at stuff like:
To see if there’s a good way to register number of clicks. I don’t really understand their code too well though, and from what I can see they only deal with single/double clicks (I may need triple and quadruple).
EDIT – uploaded the current code I’m working with. It works pretty decently most of the time. Here’s what I’ve noticed though: if I do my button testing too close together in time, the results start screwing up and under counting the clicks. I think this is because other CountDownTimers from previous attempts are still open, and when they finish, they reset certain state variables (numClicks = 0, for one). So am I misusing the timer? I can’t think of another solution though as I need some concept of elapsed time after the last click to determine when the clicking is done.
Thanks for any help.
If your
BroadcastReceiveris registered in the manifest, theBroadcastReceiverwill only exist for a single call toonReceive()— subsequent broadcasts may result in anotherBroadcastReceiverinstance. And a manifest-registeredBroadcastReceivercannot fork threads, as the whole process may get shut down onceonReceive()is over.I am skeptical that there a clean way to get your code to be reliable, as the media button simply was not designed for your intended use pattern.