Let numeric buttons rely more on touch-down on dialpad
This change lets the dialpad shows tentative digit during touch-down.
Because of some other problems we're still using touch-up for
emitting DTMF sound.
TESTED:
- Call usual phone numbers
- Try basic swipe and see a tentative number is erased
-- (e.g. Press '5' and start swiping, seeing '5' being erased during
the horizontal swipe). User should not hear DTMF sound.
- Try Voicemail by long-pressing '1'.
- Try entering '+' by long-pressing '0'. It should remove tentative
'0'.
Bug: 5749440
Change-Id: Id5332e643a6476efceb044f7d372118ffdc77377
diff --git a/res/layout/dialpad.xml b/res/layout/dialpad.xml
index 45f40f6..247bd5a 100644
--- a/res/layout/dialpad.xml
+++ b/res/layout/dialpad.xml
@@ -31,13 +31,16 @@
<TableRow
android:layout_height="0px"
android:layout_weight="1">
- <ImageButton android:id="@+id/one" style="@style/DialtactsDialpadButtonStyle"
+ <com.android.contacts.dialpad.DialpadImageButton
+ android:id="@+id/one" style="@style/DialtactsDialpadButtonStyle"
android:src="@drawable/dial_num_1"
android:contentDescription="@string/description_image_button_one" />
- <ImageButton android:id="@+id/two" style="@style/DialtactsDialpadButtonStyle"
+ <com.android.contacts.dialpad.DialpadImageButton
+ android:id="@+id/two" style="@style/DialtactsDialpadButtonStyle"
android:src="@drawable/dial_num_2"
android:contentDescription="@string/description_image_button_two" />
- <ImageButton android:id="@+id/three" style="@style/DialtactsDialpadButtonStyle"
+ <com.android.contacts.dialpad.DialpadImageButton
+ android:id="@+id/three" style="@style/DialtactsDialpadButtonStyle"
android:src="@drawable/dial_num_3"
android:contentDescription="@string/description_image_button_three" />
</TableRow>
@@ -45,13 +48,16 @@
<TableRow
android:layout_height="0px"
android:layout_weight="1">
- <ImageButton android:id="@+id/four" style="@style/DialtactsDialpadButtonStyle"
+ <com.android.contacts.dialpad.DialpadImageButton
+ android:id="@+id/four" style="@style/DialtactsDialpadButtonStyle"
android:src="@drawable/dial_num_4"
android:contentDescription="@string/description_image_button_four" />
- <ImageButton android:id="@+id/five" style="@style/DialtactsDialpadButtonStyle"
+ <com.android.contacts.dialpad.DialpadImageButton
+ android:id="@+id/five" style="@style/DialtactsDialpadButtonStyle"
android:src="@drawable/dial_num_5"
android:contentDescription="@string/description_image_button_five" />
- <ImageButton android:id="@+id/six" style="@style/DialtactsDialpadButtonStyle"
+ <com.android.contacts.dialpad.DialpadImageButton
+ android:id="@+id/six" style="@style/DialtactsDialpadButtonStyle"
android:src="@drawable/dial_num_6"
android:contentDescription="@string/description_image_button_six" />
</TableRow>
@@ -59,13 +65,16 @@
<TableRow
android:layout_height="0px"
android:layout_weight="1">
- <ImageButton android:id="@+id/seven" style="@style/DialtactsDialpadButtonStyle"
+ <com.android.contacts.dialpad.DialpadImageButton
+ android:id="@+id/seven" style="@style/DialtactsDialpadButtonStyle"
android:src="@drawable/dial_num_7"
android:contentDescription="@string/description_image_button_seven" />
- <ImageButton android:id="@+id/eight" style="@style/DialtactsDialpadButtonStyle"
+ <com.android.contacts.dialpad.DialpadImageButton
+ android:id="@+id/eight" style="@style/DialtactsDialpadButtonStyle"
android:src="@drawable/dial_num_8"
android:contentDescription="@string/description_image_button_eight" />
- <ImageButton android:id="@+id/nine" style="@style/DialtactsDialpadButtonStyle"
+ <com.android.contacts.dialpad.DialpadImageButton
+ android:id="@+id/nine" style="@style/DialtactsDialpadButtonStyle"
android:src="@drawable/dial_num_9"
android:contentDescription="@string/description_image_button_nine" />
</TableRow>
@@ -73,13 +82,16 @@
<TableRow
android:layout_height="0px"
android:layout_weight="1">
- <ImageButton android:id="@+id/star" style="@style/DialtactsDialpadButtonStyle"
+ <com.android.contacts.dialpad.DialpadImageButton
+ android:id="@+id/star" style="@style/DialtactsDialpadButtonStyle"
android:src="@drawable/dial_num_star"
android:contentDescription="@string/description_image_button_star" />
- <ImageButton android:id="@+id/zero" style="@style/DialtactsDialpadButtonStyle"
+ <com.android.contacts.dialpad.DialpadImageButton
+ android:id="@+id/zero" style="@style/DialtactsDialpadButtonStyle"
android:src="@drawable/dial_num_0"
android:contentDescription="@string/description_image_button_zero" />
- <ImageButton android:id="@+id/pound" style="@style/DialtactsDialpadButtonStyle"
+ <com.android.contacts.dialpad.DialpadImageButton
+ android:id="@+id/pound" style="@style/DialtactsDialpadButtonStyle"
android:src="@drawable/dial_num_pound"
android:contentDescription="@string/description_image_button_pound" />
</TableRow>
diff --git a/src/com/android/contacts/dialpad/DialpadFragment.java b/src/com/android/contacts/dialpad/DialpadFragment.java
index 49de9d7..c8e4d62 100644
--- a/src/com/android/contacts/dialpad/DialpadFragment.java
+++ b/src/com/android/contacts/dialpad/DialpadFragment.java
@@ -64,6 +64,7 @@
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
@@ -82,7 +83,8 @@
implements View.OnClickListener,
View.OnLongClickListener, View.OnKeyListener,
AdapterView.OnItemClickListener, TextWatcher,
- PopupMenu.OnMenuItemClickListener {
+ PopupMenu.OnMenuItemClickListener,
+ View.OnTouchListener {
private static final String TAG = DialpadFragment.class.getSimpleName();
private static final String EMPTY_NUMBER = "";
@@ -151,7 +153,7 @@
* TODO: Keep in sync with the string defined in OutgoingCallBroadcaster.java
* in Phone app until this is replaced with the ITelephony API.
*/
- static final String EXTRA_SEND_EMPTY_FLASH
+ private static final String EXTRA_SEND_EMPTY_FLASH
= "com.android.phone.extra.SEND_EMPTY_FLASH";
private String mCurrentCountryIso;
@@ -444,26 +446,30 @@
}
private void setupKeypad(View fragmentView) {
- // Setup the listeners for the buttons
- View view = fragmentView.findViewById(R.id.one);
- view.setOnClickListener(this);
- view.setOnLongClickListener(this);
+ // For numeric buttons, we rely on onTouchListener instead of onClickListener
+ // for faster event handling, while some other buttons since basically
+ // onTouch event conflicts with horizontal swipes.
+ fragmentView.findViewById(R.id.one).setOnTouchListener(this);
+ fragmentView.findViewById(R.id.two).setOnTouchListener(this);
+ fragmentView.findViewById(R.id.three).setOnTouchListener(this);
+ fragmentView.findViewById(R.id.four).setOnTouchListener(this);
+ fragmentView.findViewById(R.id.five).setOnTouchListener(this);
+ fragmentView.findViewById(R.id.six).setOnTouchListener(this);
+ fragmentView.findViewById(R.id.seven).setOnTouchListener(this);
+ fragmentView.findViewById(R.id.eight).setOnTouchListener(this);
+ fragmentView.findViewById(R.id.nine).setOnTouchListener(this);
+ fragmentView.findViewById(R.id.zero).setOnTouchListener(this);
- fragmentView.findViewById(R.id.two).setOnClickListener(this);
- fragmentView.findViewById(R.id.three).setOnClickListener(this);
- fragmentView.findViewById(R.id.four).setOnClickListener(this);
- fragmentView.findViewById(R.id.five).setOnClickListener(this);
- fragmentView.findViewById(R.id.six).setOnClickListener(this);
- fragmentView.findViewById(R.id.seven).setOnClickListener(this);
- fragmentView.findViewById(R.id.eight).setOnClickListener(this);
- fragmentView.findViewById(R.id.nine).setOnClickListener(this);
+ // Buttons other than numeric ones should use onClick as usual.
fragmentView.findViewById(R.id.star).setOnClickListener(this);
-
- view = fragmentView.findViewById(R.id.zero);
- view.setOnClickListener(this);
- view.setOnLongClickListener(this);
-
fragmentView.findViewById(R.id.pound).setOnClickListener(this);
+
+ // Long-pressing one button will initiate Voicemail.
+ fragmentView.findViewById(R.id.one).setOnLongClickListener(this);
+
+ // Long-pressing zero button will enter '+' instead.
+ fragmentView.findViewById(R.id.zero).setOnLongClickListener(this);
+
}
@Override
@@ -680,59 +686,120 @@
return false;
}
+ /**
+ * We handle the key based on the DOWN event, but we wait till the UP event to play the local
+ * DTMF tone (to avoid playing a spurious tone if the user is actually doing a swipe...)
+ */
+ @Override
+ public boolean onTouch(View view, MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ switch (view.getId()) {
+ case R.id.one: {
+ keyPressed(KeyEvent.KEYCODE_1);
+ break;
+ }
+ case R.id.two: {
+ keyPressed(KeyEvent.KEYCODE_2);
+ break;
+ }
+ case R.id.three: {
+ keyPressed(KeyEvent.KEYCODE_3);
+ break;
+ }
+ case R.id.four: {
+ keyPressed(KeyEvent.KEYCODE_4);
+ break;
+ }
+ case R.id.five: {
+ keyPressed(KeyEvent.KEYCODE_5);
+ break;
+ }
+ case R.id.six: {
+ keyPressed(KeyEvent.KEYCODE_6);
+ break;
+ }
+ case R.id.seven: {
+ keyPressed(KeyEvent.KEYCODE_7);
+ break;
+ }
+ case R.id.eight: {
+ keyPressed(KeyEvent.KEYCODE_8);
+ break;
+ }
+ case R.id.nine: {
+ keyPressed(KeyEvent.KEYCODE_9);
+ break;
+ }
+ case R.id.zero: {
+ keyPressed(KeyEvent.KEYCODE_0);
+ break;
+ }
+ default: {
+ Log.wtf(TAG, "Unexpected onTouch(ACTION_DOWN) event from: " + view);
+ break;
+ }
+ }
+ } else if (event.getAction() == MotionEvent.ACTION_UP) {
+ switch (view.getId()) {
+ case R.id.one: {
+ playTone(ToneGenerator.TONE_DTMF_1);
+ break;
+ }
+ case R.id.two: {
+ playTone(ToneGenerator.TONE_DTMF_2);
+ break;
+ }
+ case R.id.three: {
+ playTone(ToneGenerator.TONE_DTMF_3);
+ break;
+ }
+ case R.id.four: {
+ playTone(ToneGenerator.TONE_DTMF_4);
+ break;
+ }
+ case R.id.five: {
+ playTone(ToneGenerator.TONE_DTMF_5);
+ break;
+ }
+ case R.id.six: {
+ playTone(ToneGenerator.TONE_DTMF_6);
+ break;
+ }
+ case R.id.seven: {
+ playTone(ToneGenerator.TONE_DTMF_7);
+ break;
+ }
+ case R.id.eight: {
+ playTone(ToneGenerator.TONE_DTMF_8);
+ break;
+ }
+ case R.id.nine: {
+ playTone(ToneGenerator.TONE_DTMF_9);
+ break;
+ }
+ case R.id.zero: {
+ playTone(ToneGenerator.TONE_DTMF_0);
+ break;
+ }
+ default: {
+ Log.wtf(TAG, "Unexpected onTouch(ACTION_UP) event from: " + view);
+ break;
+ }
+ }
+ } else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
+ // This event will be thrown when a user starts dragging the dialpad screen,
+ // intending horizontal swipe. The system will see the event after ACTION_DOWN while
+ // it won't see relevant ACTION_UP event anymore.
+ //
+ // Here, remove the last digit already entered in the last ACTION_DOWN event.
+ removeLastOneDigitIfPossible();
+ }
+ return false;
+ }
+
@Override
public void onClick(View view) {
switch (view.getId()) {
- case R.id.one: {
- playTone(ToneGenerator.TONE_DTMF_1);
- keyPressed(KeyEvent.KEYCODE_1);
- return;
- }
- case R.id.two: {
- playTone(ToneGenerator.TONE_DTMF_2);
- keyPressed(KeyEvent.KEYCODE_2);
- return;
- }
- case R.id.three: {
- playTone(ToneGenerator.TONE_DTMF_3);
- keyPressed(KeyEvent.KEYCODE_3);
- return;
- }
- case R.id.four: {
- playTone(ToneGenerator.TONE_DTMF_4);
- keyPressed(KeyEvent.KEYCODE_4);
- return;
- }
- case R.id.five: {
- playTone(ToneGenerator.TONE_DTMF_5);
- keyPressed(KeyEvent.KEYCODE_5);
- return;
- }
- case R.id.six: {
- playTone(ToneGenerator.TONE_DTMF_6);
- keyPressed(KeyEvent.KEYCODE_6);
- return;
- }
- case R.id.seven: {
- playTone(ToneGenerator.TONE_DTMF_7);
- keyPressed(KeyEvent.KEYCODE_7);
- return;
- }
- case R.id.eight: {
- playTone(ToneGenerator.TONE_DTMF_8);
- keyPressed(KeyEvent.KEYCODE_8);
- return;
- }
- case R.id.nine: {
- playTone(ToneGenerator.TONE_DTMF_9);
- keyPressed(KeyEvent.KEYCODE_9);
- return;
- }
- case R.id.zero: {
- playTone(ToneGenerator.TONE_DTMF_0);
- keyPressed(KeyEvent.KEYCODE_0);
- return;
- }
case R.id.pound: {
playTone(ToneGenerator.TONE_DTMF_P);
keyPressed(KeyEvent.KEYCODE_POUND);
@@ -770,6 +837,11 @@
if (popup != null) {
popup.show();
}
+ return;
+ }
+ default: {
+ Log.wtf(TAG, "Unexpected onClick() event from: " + view);
+ return;
}
}
}
@@ -790,7 +862,7 @@
@Override
public boolean onLongClick(View view) {
final Editable digits = mDigits.getText();
- int id = view.getId();
+ final int id = view.getId();
switch (id) {
case R.id.deleteButton: {
digits.clear();
@@ -801,7 +873,12 @@
return true;
}
case R.id.one: {
- if (isDigitsEmpty()) {
+ // '1' may be already entered since we rely on onTouch() event for numeric buttons.
+ // Just for safety we also check if the digits field is empty or not.
+ if (isDigitsEmpty() || TextUtils.equals(mDigits.getText(), "1")) {
+ // We'll try to initiate voicemail and thus we want to remove irrelevant string.
+ removeLastOneDigitIfPossible();
+
if (isVoicemailAvailable()) {
callVoicemail();
} else if (getActivity() != null) {
@@ -815,6 +892,8 @@
return false;
}
case R.id.zero: {
+ // Remove tentative input ('0') done by onTouch().
+ removeLastOneDigitIfPossible();
keyPressed(KeyEvent.KEYCODE_PLUS);
return true;
}
@@ -829,6 +908,14 @@
return false;
}
+ private void removeLastOneDigitIfPossible() {
+ final Editable editable = mDigits.getText();
+ final int length = editable.length();
+ if (length > 0) {
+ mDigits.getText().delete(length - 1, length);
+ }
+ }
+
public void callVoicemail() {
startActivity(ContactsUtils.getVoicemailIntent());
mDigits.getText().clear(); // TODO: Fix bug 1745781
diff --git a/src/com/android/contacts/dialpad/DialpadImageButton.java b/src/com/android/contacts/dialpad/DialpadImageButton.java
new file mode 100644
index 0000000..6e01379
--- /dev/null
+++ b/src/com/android/contacts/dialpad/DialpadImageButton.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2012 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.contacts.dialpad;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.ImageButton;
+
+/**
+ * Custom {@link ImageButton} for dialpad buttons.
+ *
+ * During horizontal swipe, we want to exit "fading out" animation offered by its background
+ * just after starting the swipe.This class overrides {@link #onTouchEvent(MotionEvent)} to achieve
+ * the behavior.
+ */
+public class DialpadImageButton extends ImageButton {
+
+ public DialpadImageButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public DialpadImageButton(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ final boolean ret = super.onTouchEvent(event);
+ if (event.getAction() == MotionEvent.ACTION_CANCEL) {
+ jumpDrawablesToCurrentState();
+ }
+ return ret;
+ }
+}