Loading Android.mk +6 −2 Original line number Diff line number Diff line Loading @@ -569,10 +569,14 @@ include $(BUILD_DROIDDOC) ext_dirs := \ ../../external/apache-http/src \ ../../external/tagsoup/src ../../external/tagsoup/src \ ../../external/libphonenumber/java/src ext_src_files := $(call all-java-files-under,$(ext_dirs)) ext_res_dirs := \ ../../external/libphonenumber/java/src # ==== the library ========================================= include $(CLEAR_VARS) Loading @@ -580,7 +584,7 @@ LOCAL_SRC_FILES := $(ext_src_files) LOCAL_NO_STANDARD_LIBRARIES := true LOCAL_JAVA_LIBRARIES := core LOCAL_JAVA_RESOURCE_DIRS := $(ext_res_dirs) LOCAL_MODULE := ext LOCAL_NO_EMMA_INSTRUMENT := true Loading telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java +168 −53 Original line number Diff line number Diff line Loading @@ -16,83 +16,198 @@ package android.telephony; import com.google.i18n.phonenumbers.AsYouTypeFormatter; import com.google.i18n.phonenumbers.PhoneNumberUtil; import android.telephony.PhoneNumberUtils; import android.text.Editable; import android.text.Selection; import android.text.TextWatcher; import android.widget.TextView; import java.util.Locale; /** * Watches a {@link TextView} and if a phone number is entered will format it using * {@link PhoneNumberUtils#formatNumber(Editable, int)}. The formatting is based on * the current system locale when this object is created and future locale changes * may not take effect on this instance. * Watches a {@link TextView} and if a phone number is entered will format it. * <p> * Stop formatting when the user * <ul> * <li>Inputs non-dialable characters</li> * <li>Removes the separator in the middle of string.</li> * </ul> * <p> * The formatting will be restarted once the text is cleared. */ public class PhoneNumberFormattingTextWatcher implements TextWatcher { /** * One or more characters were removed from the end. */ private final static int STATE_REMOVE_LAST = 0; /** * One or more characters were appended. */ private final static int STATE_APPEND = 1; static private int sFormatType; static private Locale sCachedLocale; private boolean mFormatting; private boolean mDeletingHyphen; private int mHyphenStart; private boolean mDeletingBackward; /** * One or more digits were changed in the beginning or the middle of text. */ private final static int STATE_MODIFY_DIGITS = 2; /** * The changes other than the above. */ private final static int STATE_OTHER = 3; /** * The state of this change could be one value of the above */ private int mState; /** * Indicates the change was caused by ourselves. */ private boolean mSelfChange = false; /** * Indicates the formatting has been stopped. */ private boolean mStopFormatting; private AsYouTypeFormatter mFormatter; /** * The formatting is based on the current system locale and future locale changes * may not take effect on this instance. */ public PhoneNumberFormattingTextWatcher() { if (sCachedLocale == null || sCachedLocale != Locale.getDefault()) { sCachedLocale = Locale.getDefault(); sFormatType = PhoneNumberUtils.getFormatTypeForLocale(sCachedLocale); } this (Locale.getDefault() != null ? Locale.getDefault().getCountry() : "US"); } public synchronized void afterTextChanged(Editable text) { // Make sure to ignore calls to afterTextChanged caused by the work done below if (!mFormatting) { mFormatting = true; /** * The formatting is based on the given <code>countryCode</code>. * * @param countryCode the ISO 3166-1 two-letter country code that indicates the country/region * where the phone number is being entered. * * @hide */ public PhoneNumberFormattingTextWatcher(String countryCode) { mFormatter = PhoneNumberUtil.getInstance().getAsYouTypeFormatter(countryCode); } // If deleting the hyphen, also delete the char before or after that if (mDeletingHyphen && mHyphenStart > 0) { if (mDeletingBackward) { if (mHyphenStart - 1 < text.length()) { text.delete(mHyphenStart - 1, mHyphenStart); public void beforeTextChanged(CharSequence s, int start, int count, int after) { if (mSelfChange || mStopFormatting) { return; } } else if (mHyphenStart < text.length()) { text.delete(mHyphenStart, mHyphenStart + 1); if (count == 0 && s.length() == start) { // Append one or more new chars mState = STATE_APPEND; } else if (after == 0 && start + count == s.length() && count > 0) { // Remove one or more chars from the end of string. mState = STATE_REMOVE_LAST; } else if (count > 0 && !hasSeparator(s, start, count)) { // Remove the dialable chars in the begin or middle of text. mState = STATE_MODIFY_DIGITS; } else { mState = STATE_OTHER; } } PhoneNumberUtils.formatNumber(text, sFormatType); public void onTextChanged(CharSequence s, int start, int before, int count) { if (mSelfChange || mStopFormatting) { return; } if (mState == STATE_OTHER) { if (count > 0 && !hasSeparator(s, start, count)) { // User inserted the dialable characters in the middle of text. mState = STATE_MODIFY_DIGITS; } } // Check whether we should stop formatting. if (mState == STATE_APPEND && count > 0 && hasSeparator(s, start, count)) { // User appended the non-dialable character, stop formatting. stopFormatting(); } else if (mState == STATE_OTHER) { // User must insert or remove the non-dialable characters in the begin or middle of // number, stop formatting. stopFormatting(); } } mFormatting = false; public synchronized void afterTextChanged(Editable s) { if (mStopFormatting) { // Restart the formatting when all texts were clear. mStopFormatting = !(s.length() == 0); return; } if (mSelfChange) { // Ignore the change caused by s.replace(). return; } String formatted = reformat(s, Selection.getSelectionEnd(s)); if (formatted != null) { int rememberedPos = mFormatter.getRememberedPosition(); mSelfChange = true; s.replace(0, s.length(), formatted, 0, formatted.length()); // The text could be changed by other TextWatcher after we changed it. If we found the // text is not the one we were expecting, just give up calling setSelection(). if (formatted.equals(s.toString())) { Selection.setSelection(s, rememberedPos); } mSelfChange = false; } } public void beforeTextChanged(CharSequence s, int start, int count, int after) { // Check if the user is deleting a hyphen if (!mFormatting) { // Make sure user is deleting one char, without a selection final int selStart = Selection.getSelectionStart(s); final int selEnd = Selection.getSelectionEnd(s); if (s.length() > 1 // Can delete another character && count == 1 // Deleting only one character && after == 0 // Deleting && s.charAt(start) == '-' // a hyphen && selStart == selEnd) { // no selection mDeletingHyphen = true; mHyphenStart = start; // Check if the user is deleting forward or backward if (selStart == start + 1) { mDeletingBackward = true; } else { mDeletingBackward = false; /** * Generate the formatted number by ignoring all non-dialable chars and stick the cursor to the * nearest dialable char to the left. For instance, if the number is (650) 123-45678 and '4' is * removed then the cursor should be behind '3' instead of '-'. */ private String reformat(CharSequence s, int cursor) { // The index of char to the leftward of the cursor. int curIndex = cursor - 1; String formatted = null; mFormatter.clear(); char lastNonSeparator = 0; boolean hasCursor = false; int len = s.length(); for (int i = 0; i < len; i++) { char c = s.charAt(i); if (PhoneNumberUtils.isNonSeparator(c)) { if (lastNonSeparator != 0) { formatted = getFormattedNumber(lastNonSeparator, hasCursor); hasCursor = false; } } else { mDeletingHyphen = false; lastNonSeparator = c; } if (i == curIndex) { hasCursor = true; } } if (lastNonSeparator != 0) { formatted = getFormattedNumber(lastNonSeparator, hasCursor); } return formatted; } public void onTextChanged(CharSequence s, int start, int before, int count) { // Does nothing private String getFormattedNumber(char lastNonSeparator, boolean hasCursor) { return hasCursor ? mFormatter.inputDigitAndRememberPosition(lastNonSeparator) : mFormatter.inputDigit(lastNonSeparator); } private void stopFormatting() { mStopFormatting = true; mFormatter.clear(); } private boolean hasSeparator(final CharSequence s, final int start, final int count) { for (int i = start; i < start + count; i++) { char c = s.charAt(i); if (!PhoneNumberUtils.isNonSeparator(c)) { return true; } } return false; } } telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java +188 −39 Original line number Diff line number Diff line Loading @@ -13,53 +13,202 @@ * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.telephony; import android.telephony.PhoneNumberFormattingTextWatcher; import android.test.suitebuilder.annotation.SmallTest; import android.test.AndroidTestCase; import android.text.Editable; import android.text.Selection; import android.text.SpannableStringBuilder; import android.text.TextWatcher; import junit.framework.TestCase; public class PhoneNumberWatcherTest extends TestCase { @SmallTest public void testHyphenation() throws Exception { public class PhoneNumberWatcherTest extends AndroidTestCase { public void testAppendChars() { final String multiChars = "65012345"; final String formatted1 = "(650) 123-45"; TextWatcher textWatcher = getTextWatcher(); SpannableStringBuilder number = new SpannableStringBuilder(); TextWatcher tw = new PhoneNumberFormattingTextWatcher(); number.append("555-1212"); // Move the cursor to the left edge Selection.setSelection(number, 0); tw.beforeTextChanged(number, 0, 0, 1); // Insert an 8 at the beginning number.insert(0, "8"); tw.afterTextChanged(number); assertEquals("855-512-12", number.toString()); // Append more than one chars textWatcher.beforeTextChanged(number, 0, 0, multiChars.length()); number.append(multiChars); Selection.setSelection(number, number.length()); textWatcher.onTextChanged(number, 0, 0, number.length()); textWatcher.afterTextChanged(number); assertEquals(formatted1, number.toString()); assertEquals(formatted1.length(), Selection.getSelectionEnd(number)); // Append one chars final char appendChar = '6'; final String formatted2 = "(650) 123-456"; int len = number.length(); textWatcher.beforeTextChanged(number, number.length(), 0, 1); number.append(appendChar); Selection.setSelection(number, number.length()); textWatcher.onTextChanged(number, len, 0, 1); textWatcher.afterTextChanged(number); assertEquals(formatted2, number.toString()); assertEquals(formatted2.length(), Selection.getSelectionEnd(number)); } @SmallTest public void testHyphenDeletion() throws Exception { SpannableStringBuilder number = new SpannableStringBuilder(); TextWatcher tw = new PhoneNumberFormattingTextWatcher(); number.append("555-1212"); // Move the cursor to after the hyphen Selection.setSelection(number, 4); // Delete the hyphen tw.beforeTextChanged(number, 3, 1, 0); number.delete(3, 4); tw.afterTextChanged(number); // Make sure that it deleted the character before the hyphen assertEquals("551-212", number.toString()); // Make sure it deals with left edge boundary case number.insert(0, "-"); Selection.setSelection(number, 1); tw.beforeTextChanged(number, 0, 1, 0); number.delete(0, 1); tw.afterTextChanged(number); // Make sure that it deleted the character before the hyphen assertEquals("551-212", number.toString()); public void testRemoveLastChars() { final String init = "65012345678"; final String result1 = "(650) 123-4567"; TextWatcher textWatcher = getTextWatcher(); // Remove the last char. SpannableStringBuilder number = new SpannableStringBuilder(init); int len = number.length(); textWatcher.beforeTextChanged(number, len - 1, 1, 0); number.delete(len - 1, len); Selection.setSelection(number, number.length()); textWatcher.onTextChanged(number, number.length() - 1, 1, 0); textWatcher.afterTextChanged(number); assertEquals(result1, number.toString()); assertEquals(result1.length(), Selection.getSelectionEnd(number)); // Remove last 5 chars final String result2 = "(650) 123"; textWatcher.beforeTextChanged(number, number.length() - 4, 4, 0); number.delete(number.length() - 5, number.length()); Selection.setSelection(number, number.length()); textWatcher.onTextChanged(number, number.length(), 4, 0); textWatcher.afterTextChanged(number); assertEquals(result2, number.toString()); assertEquals(result2.length(), Selection.getSelectionEnd(number)); } public void testInsertChars() { final String init = "(650) 23"; final String expected1 = "(650) 123"; TextWatcher textWatcher = getTextWatcher(); // Insert one char SpannableStringBuilder number = new SpannableStringBuilder(init); textWatcher.beforeTextChanged(number, 4, 0, 1); number.insert(4, "1"); // (6501) 23 Selection.setSelection(number, 5); // make the cursor at right of 1 textWatcher.onTextChanged(number, 4, 0, 1); textWatcher.afterTextChanged(number); assertEquals(expected1, number.toString()); // the cursor should still at the right of '1' assertEquals(7, Selection.getSelectionEnd(number)); // Insert multiple chars final String expected2 = "(650) 145-6723"; textWatcher.beforeTextChanged(number, 7, 0, 4); number.insert(7, "4567"); // change to (650) 1456723 Selection.setSelection(number, 11); // the cursor is at the right of '7'. textWatcher.onTextChanged(number, 7, 0, 4); textWatcher.afterTextChanged(number); assertEquals(expected2, number.toString()); // the cursor should be still at the right of '7' assertEquals(12, Selection.getSelectionEnd(number)); } public void testStopFormatting() { final String init = "(650) 123"; final String expected1 = "(650) 123 4"; TextWatcher textWatcher = getTextWatcher(); // Append space SpannableStringBuilder number = new SpannableStringBuilder(init); textWatcher.beforeTextChanged(number, 9, 0, 2); number.insert(9, " 4"); // (6501) 23 4 Selection.setSelection(number, number.length()); // make the cursor at right of 4 textWatcher.onTextChanged(number, 9, 0, 2); textWatcher.afterTextChanged(number); assertEquals(expected1, number.toString()); // the cursor should still at the right of '1' assertEquals(expected1.length(), Selection.getSelectionEnd(number)); // Delete a ')' final String expected2 ="(650 123"; textWatcher = getTextWatcher(); number = new SpannableStringBuilder(init); textWatcher.beforeTextChanged(number, 4, 1, 0); number.delete(4, 5); // (6501 23 4 Selection.setSelection(number, 5); // make the cursor at right of 1 textWatcher.onTextChanged(number, 4, 1, 0); textWatcher.afterTextChanged(number); assertEquals(expected2, number.toString()); // the cursor should still at the right of '1' assertEquals(5, Selection.getSelectionEnd(number)); // Insert a hyphen final String expected3 ="(650) 12-3"; textWatcher = getTextWatcher(); number = new SpannableStringBuilder(init); textWatcher.beforeTextChanged(number, 8, 0, 1); number.insert(8, "-"); // (650) 12-3 Selection.setSelection(number, 9); // make the cursor at right of - textWatcher.onTextChanged(number, 8, 0, 1); textWatcher.afterTextChanged(number); assertEquals(expected3, number.toString()); // the cursor should still at the right of '-' assertEquals(9, Selection.getSelectionEnd(number)); } public void testRestartFormatting() { final String init = "(650) 123"; final String expected1 = "(650) 123 4"; TextWatcher textWatcher = getTextWatcher(); // Append space SpannableStringBuilder number = new SpannableStringBuilder(init); textWatcher.beforeTextChanged(number, 9, 0, 2); number.insert(9, " 4"); // (650) 123 4 Selection.setSelection(number, number.length()); // make the cursor at right of 4 textWatcher.onTextChanged(number, 9, 0, 2); textWatcher.afterTextChanged(number); assertEquals(expected1, number.toString()); // the cursor should still at the right of '4' assertEquals(expected1.length(), Selection.getSelectionEnd(number)); // Clear the current string, and start formatting again. int len = number.length(); textWatcher.beforeTextChanged(number, 0, len, 0); number.delete(0, len); textWatcher.onTextChanged(number, 0, len, 0); textWatcher.afterTextChanged(number); final String expected2 = "(650) 123-4"; number = new SpannableStringBuilder(init); textWatcher.beforeTextChanged(number, 9, 0, 1); number.insert(9, "4"); // (650) 1234 Selection.setSelection(number, number.length()); // make the cursor at right of 4 textWatcher.onTextChanged(number, 9, 0, 1); textWatcher.afterTextChanged(number); assertEquals(expected2, number.toString()); // the cursor should still at the right of '4' assertEquals(expected2.length(), Selection.getSelectionEnd(number)); } public void testTextChangedByOtherTextWatcher() { final TextWatcher cleanupTextWatcher = new TextWatcher() { public void afterTextChanged(Editable s) { s.clear(); } public void beforeTextChanged(CharSequence s, int start, int count, int after) { } public void onTextChanged(CharSequence s, int start, int before, int count) { } }; final String init = "(650) 123"; final String expected1 = ""; TextWatcher textWatcher = getTextWatcher(); SpannableStringBuilder number = new SpannableStringBuilder(init); textWatcher.beforeTextChanged(number, 5, 0, 1); number.insert(5, "4"); // (6504) 123 Selection.setSelection(number, 5); // make the cursor at right of 4 textWatcher.onTextChanged(number, 5, 0, 1); number.setSpan(cleanupTextWatcher, 0, number.length(), 0); textWatcher.afterTextChanged(number); assertEquals(expected1, number.toString()); } private TextWatcher getTextWatcher() { return new PhoneNumberFormattingTextWatcher("US"); } } Loading
Android.mk +6 −2 Original line number Diff line number Diff line Loading @@ -569,10 +569,14 @@ include $(BUILD_DROIDDOC) ext_dirs := \ ../../external/apache-http/src \ ../../external/tagsoup/src ../../external/tagsoup/src \ ../../external/libphonenumber/java/src ext_src_files := $(call all-java-files-under,$(ext_dirs)) ext_res_dirs := \ ../../external/libphonenumber/java/src # ==== the library ========================================= include $(CLEAR_VARS) Loading @@ -580,7 +584,7 @@ LOCAL_SRC_FILES := $(ext_src_files) LOCAL_NO_STANDARD_LIBRARIES := true LOCAL_JAVA_LIBRARIES := core LOCAL_JAVA_RESOURCE_DIRS := $(ext_res_dirs) LOCAL_MODULE := ext LOCAL_NO_EMMA_INSTRUMENT := true Loading
telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java +168 −53 Original line number Diff line number Diff line Loading @@ -16,83 +16,198 @@ package android.telephony; import com.google.i18n.phonenumbers.AsYouTypeFormatter; import com.google.i18n.phonenumbers.PhoneNumberUtil; import android.telephony.PhoneNumberUtils; import android.text.Editable; import android.text.Selection; import android.text.TextWatcher; import android.widget.TextView; import java.util.Locale; /** * Watches a {@link TextView} and if a phone number is entered will format it using * {@link PhoneNumberUtils#formatNumber(Editable, int)}. The formatting is based on * the current system locale when this object is created and future locale changes * may not take effect on this instance. * Watches a {@link TextView} and if a phone number is entered will format it. * <p> * Stop formatting when the user * <ul> * <li>Inputs non-dialable characters</li> * <li>Removes the separator in the middle of string.</li> * </ul> * <p> * The formatting will be restarted once the text is cleared. */ public class PhoneNumberFormattingTextWatcher implements TextWatcher { /** * One or more characters were removed from the end. */ private final static int STATE_REMOVE_LAST = 0; /** * One or more characters were appended. */ private final static int STATE_APPEND = 1; static private int sFormatType; static private Locale sCachedLocale; private boolean mFormatting; private boolean mDeletingHyphen; private int mHyphenStart; private boolean mDeletingBackward; /** * One or more digits were changed in the beginning or the middle of text. */ private final static int STATE_MODIFY_DIGITS = 2; /** * The changes other than the above. */ private final static int STATE_OTHER = 3; /** * The state of this change could be one value of the above */ private int mState; /** * Indicates the change was caused by ourselves. */ private boolean mSelfChange = false; /** * Indicates the formatting has been stopped. */ private boolean mStopFormatting; private AsYouTypeFormatter mFormatter; /** * The formatting is based on the current system locale and future locale changes * may not take effect on this instance. */ public PhoneNumberFormattingTextWatcher() { if (sCachedLocale == null || sCachedLocale != Locale.getDefault()) { sCachedLocale = Locale.getDefault(); sFormatType = PhoneNumberUtils.getFormatTypeForLocale(sCachedLocale); } this (Locale.getDefault() != null ? Locale.getDefault().getCountry() : "US"); } public synchronized void afterTextChanged(Editable text) { // Make sure to ignore calls to afterTextChanged caused by the work done below if (!mFormatting) { mFormatting = true; /** * The formatting is based on the given <code>countryCode</code>. * * @param countryCode the ISO 3166-1 two-letter country code that indicates the country/region * where the phone number is being entered. * * @hide */ public PhoneNumberFormattingTextWatcher(String countryCode) { mFormatter = PhoneNumberUtil.getInstance().getAsYouTypeFormatter(countryCode); } // If deleting the hyphen, also delete the char before or after that if (mDeletingHyphen && mHyphenStart > 0) { if (mDeletingBackward) { if (mHyphenStart - 1 < text.length()) { text.delete(mHyphenStart - 1, mHyphenStart); public void beforeTextChanged(CharSequence s, int start, int count, int after) { if (mSelfChange || mStopFormatting) { return; } } else if (mHyphenStart < text.length()) { text.delete(mHyphenStart, mHyphenStart + 1); if (count == 0 && s.length() == start) { // Append one or more new chars mState = STATE_APPEND; } else if (after == 0 && start + count == s.length() && count > 0) { // Remove one or more chars from the end of string. mState = STATE_REMOVE_LAST; } else if (count > 0 && !hasSeparator(s, start, count)) { // Remove the dialable chars in the begin or middle of text. mState = STATE_MODIFY_DIGITS; } else { mState = STATE_OTHER; } } PhoneNumberUtils.formatNumber(text, sFormatType); public void onTextChanged(CharSequence s, int start, int before, int count) { if (mSelfChange || mStopFormatting) { return; } if (mState == STATE_OTHER) { if (count > 0 && !hasSeparator(s, start, count)) { // User inserted the dialable characters in the middle of text. mState = STATE_MODIFY_DIGITS; } } // Check whether we should stop formatting. if (mState == STATE_APPEND && count > 0 && hasSeparator(s, start, count)) { // User appended the non-dialable character, stop formatting. stopFormatting(); } else if (mState == STATE_OTHER) { // User must insert or remove the non-dialable characters in the begin or middle of // number, stop formatting. stopFormatting(); } } mFormatting = false; public synchronized void afterTextChanged(Editable s) { if (mStopFormatting) { // Restart the formatting when all texts were clear. mStopFormatting = !(s.length() == 0); return; } if (mSelfChange) { // Ignore the change caused by s.replace(). return; } String formatted = reformat(s, Selection.getSelectionEnd(s)); if (formatted != null) { int rememberedPos = mFormatter.getRememberedPosition(); mSelfChange = true; s.replace(0, s.length(), formatted, 0, formatted.length()); // The text could be changed by other TextWatcher after we changed it. If we found the // text is not the one we were expecting, just give up calling setSelection(). if (formatted.equals(s.toString())) { Selection.setSelection(s, rememberedPos); } mSelfChange = false; } } public void beforeTextChanged(CharSequence s, int start, int count, int after) { // Check if the user is deleting a hyphen if (!mFormatting) { // Make sure user is deleting one char, without a selection final int selStart = Selection.getSelectionStart(s); final int selEnd = Selection.getSelectionEnd(s); if (s.length() > 1 // Can delete another character && count == 1 // Deleting only one character && after == 0 // Deleting && s.charAt(start) == '-' // a hyphen && selStart == selEnd) { // no selection mDeletingHyphen = true; mHyphenStart = start; // Check if the user is deleting forward or backward if (selStart == start + 1) { mDeletingBackward = true; } else { mDeletingBackward = false; /** * Generate the formatted number by ignoring all non-dialable chars and stick the cursor to the * nearest dialable char to the left. For instance, if the number is (650) 123-45678 and '4' is * removed then the cursor should be behind '3' instead of '-'. */ private String reformat(CharSequence s, int cursor) { // The index of char to the leftward of the cursor. int curIndex = cursor - 1; String formatted = null; mFormatter.clear(); char lastNonSeparator = 0; boolean hasCursor = false; int len = s.length(); for (int i = 0; i < len; i++) { char c = s.charAt(i); if (PhoneNumberUtils.isNonSeparator(c)) { if (lastNonSeparator != 0) { formatted = getFormattedNumber(lastNonSeparator, hasCursor); hasCursor = false; } } else { mDeletingHyphen = false; lastNonSeparator = c; } if (i == curIndex) { hasCursor = true; } } if (lastNonSeparator != 0) { formatted = getFormattedNumber(lastNonSeparator, hasCursor); } return formatted; } public void onTextChanged(CharSequence s, int start, int before, int count) { // Does nothing private String getFormattedNumber(char lastNonSeparator, boolean hasCursor) { return hasCursor ? mFormatter.inputDigitAndRememberPosition(lastNonSeparator) : mFormatter.inputDigit(lastNonSeparator); } private void stopFormatting() { mStopFormatting = true; mFormatter.clear(); } private boolean hasSeparator(final CharSequence s, final int start, final int count) { for (int i = start; i < start + count; i++) { char c = s.charAt(i); if (!PhoneNumberUtils.isNonSeparator(c)) { return true; } } return false; } }
telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java +188 −39 Original line number Diff line number Diff line Loading @@ -13,53 +13,202 @@ * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.telephony; import android.telephony.PhoneNumberFormattingTextWatcher; import android.test.suitebuilder.annotation.SmallTest; import android.test.AndroidTestCase; import android.text.Editable; import android.text.Selection; import android.text.SpannableStringBuilder; import android.text.TextWatcher; import junit.framework.TestCase; public class PhoneNumberWatcherTest extends TestCase { @SmallTest public void testHyphenation() throws Exception { public class PhoneNumberWatcherTest extends AndroidTestCase { public void testAppendChars() { final String multiChars = "65012345"; final String formatted1 = "(650) 123-45"; TextWatcher textWatcher = getTextWatcher(); SpannableStringBuilder number = new SpannableStringBuilder(); TextWatcher tw = new PhoneNumberFormattingTextWatcher(); number.append("555-1212"); // Move the cursor to the left edge Selection.setSelection(number, 0); tw.beforeTextChanged(number, 0, 0, 1); // Insert an 8 at the beginning number.insert(0, "8"); tw.afterTextChanged(number); assertEquals("855-512-12", number.toString()); // Append more than one chars textWatcher.beforeTextChanged(number, 0, 0, multiChars.length()); number.append(multiChars); Selection.setSelection(number, number.length()); textWatcher.onTextChanged(number, 0, 0, number.length()); textWatcher.afterTextChanged(number); assertEquals(formatted1, number.toString()); assertEquals(formatted1.length(), Selection.getSelectionEnd(number)); // Append one chars final char appendChar = '6'; final String formatted2 = "(650) 123-456"; int len = number.length(); textWatcher.beforeTextChanged(number, number.length(), 0, 1); number.append(appendChar); Selection.setSelection(number, number.length()); textWatcher.onTextChanged(number, len, 0, 1); textWatcher.afterTextChanged(number); assertEquals(formatted2, number.toString()); assertEquals(formatted2.length(), Selection.getSelectionEnd(number)); } @SmallTest public void testHyphenDeletion() throws Exception { SpannableStringBuilder number = new SpannableStringBuilder(); TextWatcher tw = new PhoneNumberFormattingTextWatcher(); number.append("555-1212"); // Move the cursor to after the hyphen Selection.setSelection(number, 4); // Delete the hyphen tw.beforeTextChanged(number, 3, 1, 0); number.delete(3, 4); tw.afterTextChanged(number); // Make sure that it deleted the character before the hyphen assertEquals("551-212", number.toString()); // Make sure it deals with left edge boundary case number.insert(0, "-"); Selection.setSelection(number, 1); tw.beforeTextChanged(number, 0, 1, 0); number.delete(0, 1); tw.afterTextChanged(number); // Make sure that it deleted the character before the hyphen assertEquals("551-212", number.toString()); public void testRemoveLastChars() { final String init = "65012345678"; final String result1 = "(650) 123-4567"; TextWatcher textWatcher = getTextWatcher(); // Remove the last char. SpannableStringBuilder number = new SpannableStringBuilder(init); int len = number.length(); textWatcher.beforeTextChanged(number, len - 1, 1, 0); number.delete(len - 1, len); Selection.setSelection(number, number.length()); textWatcher.onTextChanged(number, number.length() - 1, 1, 0); textWatcher.afterTextChanged(number); assertEquals(result1, number.toString()); assertEquals(result1.length(), Selection.getSelectionEnd(number)); // Remove last 5 chars final String result2 = "(650) 123"; textWatcher.beforeTextChanged(number, number.length() - 4, 4, 0); number.delete(number.length() - 5, number.length()); Selection.setSelection(number, number.length()); textWatcher.onTextChanged(number, number.length(), 4, 0); textWatcher.afterTextChanged(number); assertEquals(result2, number.toString()); assertEquals(result2.length(), Selection.getSelectionEnd(number)); } public void testInsertChars() { final String init = "(650) 23"; final String expected1 = "(650) 123"; TextWatcher textWatcher = getTextWatcher(); // Insert one char SpannableStringBuilder number = new SpannableStringBuilder(init); textWatcher.beforeTextChanged(number, 4, 0, 1); number.insert(4, "1"); // (6501) 23 Selection.setSelection(number, 5); // make the cursor at right of 1 textWatcher.onTextChanged(number, 4, 0, 1); textWatcher.afterTextChanged(number); assertEquals(expected1, number.toString()); // the cursor should still at the right of '1' assertEquals(7, Selection.getSelectionEnd(number)); // Insert multiple chars final String expected2 = "(650) 145-6723"; textWatcher.beforeTextChanged(number, 7, 0, 4); number.insert(7, "4567"); // change to (650) 1456723 Selection.setSelection(number, 11); // the cursor is at the right of '7'. textWatcher.onTextChanged(number, 7, 0, 4); textWatcher.afterTextChanged(number); assertEquals(expected2, number.toString()); // the cursor should be still at the right of '7' assertEquals(12, Selection.getSelectionEnd(number)); } public void testStopFormatting() { final String init = "(650) 123"; final String expected1 = "(650) 123 4"; TextWatcher textWatcher = getTextWatcher(); // Append space SpannableStringBuilder number = new SpannableStringBuilder(init); textWatcher.beforeTextChanged(number, 9, 0, 2); number.insert(9, " 4"); // (6501) 23 4 Selection.setSelection(number, number.length()); // make the cursor at right of 4 textWatcher.onTextChanged(number, 9, 0, 2); textWatcher.afterTextChanged(number); assertEquals(expected1, number.toString()); // the cursor should still at the right of '1' assertEquals(expected1.length(), Selection.getSelectionEnd(number)); // Delete a ')' final String expected2 ="(650 123"; textWatcher = getTextWatcher(); number = new SpannableStringBuilder(init); textWatcher.beforeTextChanged(number, 4, 1, 0); number.delete(4, 5); // (6501 23 4 Selection.setSelection(number, 5); // make the cursor at right of 1 textWatcher.onTextChanged(number, 4, 1, 0); textWatcher.afterTextChanged(number); assertEquals(expected2, number.toString()); // the cursor should still at the right of '1' assertEquals(5, Selection.getSelectionEnd(number)); // Insert a hyphen final String expected3 ="(650) 12-3"; textWatcher = getTextWatcher(); number = new SpannableStringBuilder(init); textWatcher.beforeTextChanged(number, 8, 0, 1); number.insert(8, "-"); // (650) 12-3 Selection.setSelection(number, 9); // make the cursor at right of - textWatcher.onTextChanged(number, 8, 0, 1); textWatcher.afterTextChanged(number); assertEquals(expected3, number.toString()); // the cursor should still at the right of '-' assertEquals(9, Selection.getSelectionEnd(number)); } public void testRestartFormatting() { final String init = "(650) 123"; final String expected1 = "(650) 123 4"; TextWatcher textWatcher = getTextWatcher(); // Append space SpannableStringBuilder number = new SpannableStringBuilder(init); textWatcher.beforeTextChanged(number, 9, 0, 2); number.insert(9, " 4"); // (650) 123 4 Selection.setSelection(number, number.length()); // make the cursor at right of 4 textWatcher.onTextChanged(number, 9, 0, 2); textWatcher.afterTextChanged(number); assertEquals(expected1, number.toString()); // the cursor should still at the right of '4' assertEquals(expected1.length(), Selection.getSelectionEnd(number)); // Clear the current string, and start formatting again. int len = number.length(); textWatcher.beforeTextChanged(number, 0, len, 0); number.delete(0, len); textWatcher.onTextChanged(number, 0, len, 0); textWatcher.afterTextChanged(number); final String expected2 = "(650) 123-4"; number = new SpannableStringBuilder(init); textWatcher.beforeTextChanged(number, 9, 0, 1); number.insert(9, "4"); // (650) 1234 Selection.setSelection(number, number.length()); // make the cursor at right of 4 textWatcher.onTextChanged(number, 9, 0, 1); textWatcher.afterTextChanged(number); assertEquals(expected2, number.toString()); // the cursor should still at the right of '4' assertEquals(expected2.length(), Selection.getSelectionEnd(number)); } public void testTextChangedByOtherTextWatcher() { final TextWatcher cleanupTextWatcher = new TextWatcher() { public void afterTextChanged(Editable s) { s.clear(); } public void beforeTextChanged(CharSequence s, int start, int count, int after) { } public void onTextChanged(CharSequence s, int start, int before, int count) { } }; final String init = "(650) 123"; final String expected1 = ""; TextWatcher textWatcher = getTextWatcher(); SpannableStringBuilder number = new SpannableStringBuilder(init); textWatcher.beforeTextChanged(number, 5, 0, 1); number.insert(5, "4"); // (6504) 123 Selection.setSelection(number, 5); // make the cursor at right of 4 textWatcher.onTextChanged(number, 5, 0, 1); number.setSpan(cleanupTextWatcher, 0, number.length(), 0); textWatcher.afterTextChanged(number); assertEquals(expected1, number.toString()); } private TextWatcher getTextWatcher() { return new PhoneNumberFormattingTextWatcher("US"); } }