Index: chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/CreditCardNumberFormattingTextWatcher.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/CreditCardNumberFormattingTextWatcher.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/CreditCardNumberFormattingTextWatcher.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..42b98e894b241603062d2edaf6ae216eb60a41ae |
--- /dev/null |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/CreditCardNumberFormattingTextWatcher.java |
@@ -0,0 +1,99 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.chromium.chrome.browser.preferences.autofill; |
+ |
+import android.text.Editable; |
+import android.text.TextUtils; |
+import android.text.TextWatcher; |
+ |
+/** |
+ * Watch a TextView and if a credit card number is entered, it will format the number. |
+ * Disable formatting when user: |
+ * 1. Inputs dashes or spaces. |
+ * 2. Removes separators in the middle of the string |
+ * 3. Enters a number longer than 16 digits. |
+ * |
+ * Formatting will be re-enabled once text is cleared. |
+ */ |
+public class CreditCardNumberFormattingTextWatcher implements TextWatcher { |
+ /** Character for card number section separator. */ |
+ private static final String SEPARATOR = " "; |
+ |
+ /** |
+ * Whether to format the credit card number. If true, spaces will be inserted |
+ * automatically between each group of 4 digits in the credit card number as the user types. |
+ * This is set to false if the user types a dash or deletes one of the auto-inserted spaces. |
+ */ |
+ private boolean mFormattingEnabled = true; |
+ |
+ /** |
+ * Whether the change was caused by ourselves. |
+ * This is set true when we are manipulating the text of EditText, |
+ * and all callback functions should check this boolean to avoid infinite recursion. |
+ */ |
+ private boolean mSelfChange = false; |
+ |
+ @Override |
+ public void onTextChanged(CharSequence s, int start, int before, int count) { |
+ if (mSelfChange || !mFormattingEnabled) return; |
+ // If user enters non-digit characters, do not format. |
+ if (count > 0 && hasDashOrSpace(s, start, count)) { |
+ mFormattingEnabled = false; |
+ } |
+ } |
+ |
+ @Override |
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) { |
+ if (mSelfChange || !mFormattingEnabled) return; |
+ // If user deletes non-digit characters, do not format. |
+ if (count > 0 && hasDashOrSpace(s, start, count)) { |
+ mFormattingEnabled = false; |
+ } |
+ } |
+ |
+ @Override |
+ public void afterTextChanged(Editable s) { |
+ if (mSelfChange) return; |
+ mSelfChange = true; |
+ |
+ if (mFormattingEnabled) { |
+ removeSeparators(s); |
+ // If number is too long, do not format it and remove all |
+ // previous separators. |
+ if (s.length() > 16) { |
+ mFormattingEnabled = false; |
+ } else { |
+ insertSeparators(s); |
+ } |
+ } |
+ // If user clears the input, re-enable formatting |
+ if (s.length() == 0) mFormattingEnabled = true; |
+ |
+ mSelfChange = false; |
+ } |
+ |
+ public static void removeSeparators(Editable s) { |
+ int index = TextUtils.indexOf(s, SEPARATOR); |
+ while (index >= 0) { |
+ s.delete(index, index + 1); |
+ index = TextUtils.indexOf(s, SEPARATOR, index + 1); |
+ } |
+ } |
+ |
+ public static void insertSeparators(Editable s) { |
+ final int[] positions = {4, 9, 14 }; |
+ for (int i : positions) { |
+ if (s.length() > i) { |
+ s.insert(i, SEPARATOR); |
+ } |
+ } |
+ } |
+ |
+ public static boolean hasDashOrSpace(final CharSequence s, final int start, |
+ final int count) { |
+ return TextUtils.indexOf(s, " ", start, start + count) != -1 |
+ || TextUtils.indexOf(s, "-", start, start + count) != -1; |
+ } |
+} |