package com.azimolabs.maskformatter; import android.os.Build; import android.text.Editable; import android.text.InputType; import android.text.TextWatcher; import android.widget.EditText; /** * Created by maciek on 16.03.2016. */ public class MaskFormatter implements TextWatcher { private static final char SPACE = ' '; private final String mask; private final EditText maskedField; private final char maskCharacter; private boolean editTextChange; private int newIndex; private String textBefore; private int selectionBefore; private int passwordMask; public MaskFormatter(String mask, EditText maskedField) { this(mask, maskedField, SPACE); } public MaskFormatter(String mask, EditText maskedField, char maskCharacter) { this.mask = mask; this.maskedField = maskedField; this.maskCharacter = maskCharacter; this.passwordMask = getPasswordMask(maskedField); setInputTypeBasedOnMask(); } private int getPasswordMask(EditText maskedField) { int inputType = maskedField.getInputType(); int maskedFieldPasswordMask = (inputType & InputType.TYPE_TEXT_VARIATION_PASSWORD | inputType & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { maskedFieldPasswordMask |= inputType & InputType.TYPE_NUMBER_VARIATION_PASSWORD; maskedFieldPasswordMask |= inputType & InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD; } return maskedFieldPasswordMask; } @Override public void beforeTextChanged(CharSequence s, int index, int toBeReplacedCount, int addedCount) { textBefore = s.toString(); selectionBefore = maskedField.getSelectionEnd(); } @Override public void onTextChanged(CharSequence s, int index, int replacedCount, int addedCount) { if (editTextChange) { maskedField.setSelection(newIndex); editTextChange = false; return; } try { String appliedMaskString = applyMask(s.toString()); if (!appliedMaskString.equals(s.toString())) { editTextChange = true; newIndex = countNewIndex(addedCount, appliedMaskString); maskedField.setText(appliedMaskString); } } catch (InvalidTextException ie) { editTextChange = true; newIndex = selectionBefore; maskedField.setText(textBefore); } } private int countNewIndex(int addedCount, String appliedMaskString) { if (appliedMaskString.length() == 0) { return 0; } if (addedCount < 1) { return newIndexForRemovingCharacters(appliedMaskString); } return newIndexForAddingCharacters(appliedMaskString); } private int newIndexForRemovingCharacters(String appliedMaskString) { if (selectionBefore > appliedMaskString.length()) { selectionBefore = appliedMaskString.length(); } else { selectionBefore = selectionBefore - 1; } if (selectionBefore < 0) { return 0; } if (selectionBefore - 1 >= 0 && appliedMaskString.charAt(selectionBefore - 1) == maskCharacter) { return selectionBefore - 1; } return selectionBefore; } private int newIndexForAddingCharacters(String appliedMaskString) { if (selectionBefore >= appliedMaskString.length()) { return appliedMaskString.length(); } if (appliedMaskString.charAt(selectionBefore) == maskCharacter) { return selectionBefore + 2; } return selectionBefore + 1; } @Override public void afterTextChanged(Editable s) { if (editTextChange) { maskedField.setSelection(newIndex); } setInputTypeBasedOnMask(); } private String applyMask(String newValue) throws InvalidTextException { String newValueWithoutSpaces = newValue.replaceAll(String.valueOf(maskCharacter), ""); StringBuilder sb = new StringBuilder(); int index = 0; for (char c : newValueWithoutSpaces.toCharArray()) { if (index >= mask.length()) { throw new InvalidTextException(); } while (mask.charAt(index) == maskCharacter) { sb.append(maskCharacter); index++; } sb.append(applyMaskToChar(c, index)); index++; } return sb.toString(); } private char applyMaskToChar(char c, int maskIndex) throws InvalidTextException { return CharTransforms.transformChar(c, mask.charAt(maskIndex)); } private void setInputTypeBasedOnMask() { int selection = maskedField.getSelectionEnd(); if (selection >= mask.length()) { return; } char maskChar = getFirstNotWhiteCharFromMask(); if (maskChar == maskCharacter) { return; } maskedField.setInputType(passwordMask | CharInputType.getKeyboardTypeForNextChar(maskChar)); } private char getFirstNotWhiteCharFromMask() { int maskIndex = maskedField.getSelectionEnd(); while (maskIndex < mask.length() && mask.charAt(maskIndex) == maskCharacter) { maskIndex++; } return mask.charAt(maskIndex); } public String getRawTextValue() { return maskedField.getText().toString().replaceAll(String.valueOf(maskCharacter), ""); } }