/*
* Copyright 2015 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.talkback.volumebutton;
import android.view.KeyEvent;
import android.view.ViewConfiguration;
import java.util.concurrent.TimeUnit;
public class DoubleVolumeButtonTreeShortPressPatternMatcher extends VolumeButtonPatternMatcher {
private static final long MULTIPLE_TAP_TIMEOUT = TimeUnit.MINUTES.toMillis(1);
private static final long LONG_PRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout();
private int mDoubleButtonPresses;
private long mLastDoubleButtonPressEndTimestamp;
private VolumeButtonAction mLastVolumeUpAction;
private VolumeButtonAction mLastVolumeDownAction;
public DoubleVolumeButtonTreeShortPressPatternMatcher() {
super(VolumeButtonPatternDetector.TWO_BUTTONS_THREE_PRESS_PATTERN,
VolumeButtonPatternDetector.TWO_BUTTONS);
}
@Override
public void onKeyEvent(KeyEvent keyEvent) {
if (keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_DOWN &&
keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_UP) {
return;
}
if (interruptActionSequence(keyEvent)) {
clear();
}
if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
handleActionDownEvent(keyEvent);
} else {
handleActionUpEvent(keyEvent);
}
updateCounters();
}
private void handleActionDownEvent(KeyEvent event) {
VolumeButtonAction action = createAction(event);
if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP) {
mLastVolumeUpAction = action;
} else {
mLastVolumeDownAction = action;
}
}
private void handleActionUpEvent(KeyEvent event) {
VolumeButtonAction action;
if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP) {
action = mLastVolumeUpAction;
} else {
action = mLastVolumeDownAction;
}
if (action != null) {
action.pressed = false;
action.endTimestamp = event.getEventTime();
}
}
private boolean interruptActionSequence(KeyEvent keyEvent) {
if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
return isDownEventInterruptsActionSequence(keyEvent);
} else {
return isUpEventInterruptsActionSequence(keyEvent);
}
}
private boolean isDownEventInterruptsActionSequence(KeyEvent keyEvent) {
if (mDoubleButtonPresses != 0 &&
keyEvent.getEventTime() - mLastDoubleButtonPressEndTimestamp > MULTIPLE_TAP_TIMEOUT) {
// too long timeout between previous double volume buttons pushes
return true;
}
VolumeButtonAction otherAction = getOtherAction(keyEvent);
//noinspection RedundantIfStatement
if (otherAction != null && !otherAction.pressed) {
// other button was released before current action pressed
return true;
}
return false;
}
private boolean isUpEventInterruptsActionSequence(KeyEvent keyEvent) {
VolumeButtonAction currentAction = getCurrentAction(keyEvent);
VolumeButtonAction otherAction = getOtherAction(keyEvent);
if (currentAction == null) {
// up on non-pressed button
return true;
}
if (otherAction == null) {
// click detected while other button was not pressed
return true;
}
//noinspection RedundantIfStatement
if (keyEvent.getEventTime() - currentAction.startTimestamp > LONG_PRESS_TIMEOUT) {
// button was pressed too long
return true;
}
return false;
}
private VolumeButtonAction getCurrentAction(KeyEvent keyEvent) {
if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP) {
return mLastVolumeUpAction;
} else {
return mLastVolumeDownAction;
}
}
private VolumeButtonAction getOtherAction(KeyEvent keyEvent) {
if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP) {
return mLastVolumeDownAction;
} else {
return mLastVolumeUpAction;
}
}
private void updateCounters() {
if (mLastVolumeUpAction != null && !mLastVolumeUpAction.pressed &&
mLastVolumeDownAction != null && !mLastVolumeDownAction.pressed) {
mDoubleButtonPresses++;
mLastDoubleButtonPressEndTimestamp = Math.max(mLastVolumeUpAction.endTimestamp,
mLastVolumeDownAction.endTimestamp);
mLastVolumeUpAction = null;
mLastVolumeDownAction = null;
}
}
@Override
public boolean checkMatch() {
return mDoubleButtonPresses >= 3;
}
@Override
public void clear() {
mDoubleButtonPresses = 0;
mLastDoubleButtonPressEndTimestamp = 0;
mLastVolumeUpAction = null;
mLastVolumeDownAction = null;
}
}