Skip to content

Commit ab624c2

Browse files
author
Jeff Brown
committed
Use FLAG_LONG_PRESS for headset long press interactions.
Handle canceled key events correctly and don't synthesize key events in that case. Unfortunately, the state machine was confused by some sequences of key events that it might receive from the input dispatcher when new activities take focus during a long-press on the headset key. The audio service may receive a cancel event intended for the old window, followed by a repeated down and finally an up for the new window. Simplified this down to just two booleans. Bug: 6484717 Change-Id: I9587d0a5e282419ef4d7c17665940682aacea96a
1 parent 9cb376e commit ab624c2

File tree

1 file changed

+25
-83
lines changed

1 file changed

+25
-83
lines changed

media/java/android/media/AudioService.java

Lines changed: 25 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -3699,38 +3699,15 @@ private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
36993699
}
37003700

37013701
/**
3702-
* The minimum duration during which a user must press to trigger voice-based interactions
3703-
*/
3704-
private final static int MEDIABUTTON_LONG_PRESS_DURATION_MS = 300;
3705-
/**
3706-
* The different states of the state machine to handle the launch of voice-based interactions,
3707-
* stored in mVoiceButtonState.
3708-
*/
3709-
private final static int VOICEBUTTON_STATE_IDLE = 0;
3710-
private final static int VOICEBUTTON_STATE_DOWN = 1;
3711-
private final static int VOICEBUTTON_STATE_DOWN_IGNORE_NEW = 2;
3712-
/**
3713-
* The different actions after state transitions on mVoiceButtonState.
3702+
* The different actions performed in response to a voice button key event.
37143703
*/
37153704
private final static int VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS = 1;
37163705
private final static int VOICEBUTTON_ACTION_START_VOICE_INPUT = 2;
37173706
private final static int VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS = 3;
37183707

37193708
private final Object mVoiceEventLock = new Object();
3720-
private int mVoiceButtonState = VOICEBUTTON_STATE_IDLE;
3721-
private long mVoiceButtonDownTime = 0;
3722-
3723-
/**
3724-
* Log an error when an unexpected action is encountered in the state machine to filter
3725-
* key events.
3726-
* @param keyAction the unexpected action of the key event being filtered
3727-
* @param stateName the string corresponding to the state in which the error occurred
3728-
*/
3729-
private static void logErrorForKeyAction(int keyAction, String stateName) {
3730-
Log.e(TAG, "unexpected action "
3731-
+ KeyEvent.actionToString(keyAction)
3732-
+ " in " + stateName + " state");
3733-
}
3709+
private boolean mVoiceButtonDown;
3710+
private boolean mVoiceButtonHandled;
37343711

37353712
/**
37363713
* Filter key events that may be used for voice-based interactions
@@ -3740,67 +3717,32 @@ private static void logErrorForKeyAction(int keyAction, String stateName) {
37403717
* is dispatched.
37413718
*/
37423719
private void filterVoiceInputKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
3720+
if (DEBUG_RC) {
3721+
Log.v(TAG, "voice input key event: " + keyEvent + ", needWakeLock=" + needWakeLock);
3722+
}
3723+
37433724
int voiceButtonAction = VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS;
37443725
int keyAction = keyEvent.getAction();
37453726
synchronized (mVoiceEventLock) {
3746-
// state machine on mVoiceButtonState
3747-
switch (mVoiceButtonState) {
3748-
3749-
case VOICEBUTTON_STATE_IDLE:
3750-
if (keyAction == KeyEvent.ACTION_DOWN) {
3751-
mVoiceButtonDownTime = keyEvent.getDownTime();
3752-
// valid state transition
3753-
mVoiceButtonState = VOICEBUTTON_STATE_DOWN;
3754-
} else if (keyAction == KeyEvent.ACTION_UP) {
3755-
// no state transition
3756-
// action is still VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS
3757-
} else {
3758-
logErrorForKeyAction(keyAction, "VOICEBUTTON_STATE_IDLE");
3759-
}
3760-
break;
3761-
3762-
case VOICEBUTTON_STATE_DOWN:
3763-
if ((keyEvent.getEventTime() - mVoiceButtonDownTime)
3764-
>= MEDIABUTTON_LONG_PRESS_DURATION_MS) {
3765-
// press was long enough, start voice-based interactions, regardless of
3766-
// whether this was a DOWN or UP key event
3767-
voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT;
3768-
if (keyAction == KeyEvent.ACTION_UP) {
3769-
// done tracking the key press, so transition back to idle state
3770-
mVoiceButtonState = VOICEBUTTON_STATE_IDLE;
3771-
} else if (keyAction == KeyEvent.ACTION_DOWN) {
3772-
// no need to observe the upcoming key events
3773-
mVoiceButtonState = VOICEBUTTON_STATE_DOWN_IGNORE_NEW;
3774-
} else {
3775-
logErrorForKeyAction(keyAction, "VOICEBUTTON_STATE_DOWN");
3776-
}
3777-
} else {
3778-
if (keyAction == KeyEvent.ACTION_UP) {
3779-
// press wasn't long enough, simulate complete key press
3780-
voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS;
3781-
// not tracking the key press anymore, so transition back to idle state
3782-
mVoiceButtonState = VOICEBUTTON_STATE_IDLE;
3783-
} else if (keyAction == KeyEvent.ACTION_DOWN) {
3784-
// no state transition
3785-
// action is still VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS
3786-
} else {
3787-
logErrorForKeyAction(keyAction, "VOICEBUTTON_STATE_DOWN");
3788-
}
3789-
}
3790-
break;
3791-
3792-
case VOICEBUTTON_STATE_DOWN_IGNORE_NEW:
3793-
if (keyAction == KeyEvent.ACTION_UP) {
3794-
// done tracking the key press, so transition back to idle state
3795-
mVoiceButtonState = VOICEBUTTON_STATE_IDLE;
3796-
// action is still VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS
3797-
} else if (keyAction == KeyEvent.ACTION_DOWN) {
3798-
// no state transition: we've already launched voice-based interactions
3799-
// action is still VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS
3800-
} else {
3801-
logErrorForKeyAction(keyAction, "VOICEBUTTON_STATE_DOWN_IGNORE_NEW");
3727+
if (keyAction == KeyEvent.ACTION_DOWN) {
3728+
if (keyEvent.getRepeatCount() == 0) {
3729+
// initial down
3730+
mVoiceButtonDown = true;
3731+
mVoiceButtonHandled = false;
3732+
} else if (mVoiceButtonDown && !mVoiceButtonHandled
3733+
&& (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
3734+
// long-press, start voice-based interactions
3735+
mVoiceButtonHandled = true;
3736+
voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT;
3737+
}
3738+
} else if (keyAction == KeyEvent.ACTION_UP) {
3739+
if (mVoiceButtonDown) {
3740+
// voice button up
3741+
mVoiceButtonDown = false;
3742+
if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
3743+
voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS;
38023744
}
3803-
break;
3745+
}
38043746
}
38053747
}//synchronized (mVoiceEventLock)
38063748

0 commit comments

Comments
 (0)