summaryrefslogtreecommitdiff
path: root/java/com/android/incallui/DtmfKeyListener.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/android/incallui/DtmfKeyListener.java')
-rw-r--r--java/com/android/incallui/DtmfKeyListener.java156
1 files changed, 156 insertions, 0 deletions
diff --git a/java/com/android/incallui/DtmfKeyListener.java b/java/com/android/incallui/DtmfKeyListener.java
new file mode 100644
index 000000000..a2a0de09e
--- /dev/null
+++ b/java/com/android/incallui/DtmfKeyListener.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.incallui;
+
+import android.support.annotation.NonNull;
+import android.text.Editable;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.method.DialerKeyListener;
+import android.view.KeyEvent;
+import android.view.View;
+import com.android.dialer.common.LogUtil;
+
+/**
+ * Key listener specialized to deal with Dtmf codes.
+ *
+ * <p>This listener will listen for valid Dtmf characters, and in response will inform the
+ * associated presenter of the character. As an implementation of {@link DialerKeyListener}, this
+ * class will listen for <b>hardware keyboard</b> events.
+ *
+ * <p>From legacy documentation:
+ *
+ * <ul>
+ * <li>Ignores the backspace since it is irrelevant.
+ * <li>Allow ONLY valid DTMF characters to generate a tone and be sent as a DTMF code.
+ * <li>All other remaining characters are handled by the superclass.
+ * <li>This code is purely here to handle events from the hardware keyboard while the DTMF dialpad
+ * is up.
+ * </ul>
+ */
+final class DtmfKeyListener extends DialerKeyListener {
+ /**
+ * Overrides the characters used in {@link DialerKeyListener#CHARACTERS} These are the valid dtmf
+ * characters.
+ */
+ private static final char[] VALID_DTMF_CHARACTERS =
+ new char[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '#', '*'};
+
+ /**
+ * Spannable used to call {@link DialerKeyListener#lookup(KeyEvent, Spannable)}, so it's not
+ * necessary to copy the implementation.
+ *
+ * <p>The Spannable is only used to determine which meta keys are pressed, e.g. shift, alt, see
+ * {@link android.text.method.MetaKeyKeyListener#getMetaState(CharSequence)}, so using a dummy
+ * value is fine here.
+ */
+ private static final Spannable EMPTY_SPANNABLE = new SpannableString("");
+
+ private final DialpadPresenter presenter;
+
+ DtmfKeyListener(@NonNull DialpadPresenter presenter) {
+ this.presenter = presenter;
+ }
+
+ @Override
+ protected char[] getAcceptedChars() {
+ return VALID_DTMF_CHARACTERS;
+ }
+
+ @Override
+ public boolean backspace(View view, Editable content, int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ /**
+ * Responds to keyDown events by firing a Dtmf tone, if the given event corresponds is a {@link
+ * #VALID_DTMF_CHARACTERS}.
+ *
+ * @return {@code true} if the event was handled.
+ */
+ @Override
+ public boolean onKeyDown(View view, Editable content, int keyCode, KeyEvent event) {
+ LogUtil.i("DtmfKeyListener.onKeyDown", "overload");
+ if (!super.onKeyDown(view, content, keyCode, event)) {
+ LogUtil.i("DtmfKeyListener.onKeyDown", "parent type didn't support event");
+ return false;
+ }
+
+ return onKeyDown(event);
+ }
+
+ /**
+ * Version of {@link #onKeyDown(View, Editable, int, KeyEvent)} used when a View/Editable isn't
+ * available.
+ */
+ boolean onKeyDown(KeyEvent event) {
+ LogUtil.enterBlock("DtmfKeyListener.onKeyDown");
+ if (event.getRepeatCount() != 0) {
+ LogUtil.i("DtmfKeyListener.onKeyDown", "long press, ignoring");
+ return false;
+ }
+
+ char c = (char) lookup(event, EMPTY_SPANNABLE);
+
+ if (!ok(getAcceptedChars(), c)) {
+ LogUtil.i("DtmfKeyListener.onKeyDown", "not an accepted character");
+ return false;
+ }
+
+ presenter.processDtmf(c);
+ return true;
+ }
+
+ /**
+ * Responds to keyUp events by stopping any playing Dtmf tone if the given event corresponds is a
+ * {@link #VALID_DTMF_CHARACTERS}.
+ *
+ * <p>Null events also stop the Dtmf tone.
+ *
+ * @return {@code true} if the event was handled
+ */
+ @Override
+ public boolean onKeyUp(View view, Editable content, int keyCode, KeyEvent event) {
+ LogUtil.i("DtmfKeyListener.onKeyUp", "overload");
+ super.onKeyUp(view, content, keyCode, event);
+
+ return onKeyUp(event);
+ }
+
+ /**
+ * Handle individual keyup events.
+ *
+ * @param event is the event we are trying to stop. If this is null, then we just force-stop the
+ * last tone without checking if the event is an acceptable dialer event.
+ */
+ boolean onKeyUp(KeyEvent event) {
+ LogUtil.enterBlock("DtmfKeyListener.onKeyUp");
+ if (event == null) {
+ return true;
+ }
+
+ char c = (char) lookup(event, EMPTY_SPANNABLE);
+
+ if (!ok(getAcceptedChars(), c)) {
+ LogUtil.i("DtmfKeyListener.onKeyUp", "not an accepted character");
+ return false;
+ }
+
+ presenter.stopDtmf();
+ return true;
+ }
+}