package com.andreabaccega.widget; import android.app.AlertDialog; import android.content.Context; import android.os.Bundle; import android.preference.EditTextPreference; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; /** * A validating {@link android.preference.EditTextPreference} validation is performed when the OK * or AlertDialog.BUTTON_POSITIVE button is clicked. When invalid an error * message is displayed and the EditTextPreference is not dismissed */ public class ValidatingEditTextPreference extends EditTextPreference { public ValidatingEditTextPreference(Context context) { super(context); // FIXME how should this constructor be handled throw new RuntimeException("Not supported"); } public ValidatingEditTextPreference(Context context, AttributeSet attrs) { super(context, attrs); editTextValidator = new DefaultEditTextValidator(getEditText(), attrs, context); } public ValidatingEditTextPreference(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); editTextValidator = new DefaultEditTextValidator(getEditText(), attrs, context); } public EditTextValidator getEditTextValidator() { return editTextValidator; } public void setEditTextValidator(EditTextValidator editTextValidator) { this.editTextValidator = editTextValidator; } @Override protected void showDialog(Bundle state) { super.showDialog(state); // If the dialog isn't an instance of alert dialog this code is useless if (super.getDialog() instanceof AlertDialog) { final AlertDialog theDialog = (AlertDialog) super.getDialog(); // get originalBottomPadding to know when adjust the underlying // layouts bottom padding (ie has room already // been created for an error message) int padding = Integer.MIN_VALUE; try { padding = ((LinearLayout) getEditText().getParent()) .getPaddingBottom(); } catch (Exception e) { // some exception thrown. Unable to do increase space for error // message } final int originalBottomPadding = padding; Button b = theDialog.getButton(AlertDialog.BUTTON_POSITIVE); // attach our validating on click listener ValidatingOnClickListener l = new ValidatingOnClickListener( originalBottomPadding, theDialog); b.setOnClickListener(l); // add an editor action listener for the 'done/next' buttons on a // soft keyboard getEditText().setOnEditorActionListener(l); } } private final class ValidatingOnClickListener implements View.OnClickListener, OnEditorActionListener { private ValidatingOnClickListener(int originalBottomPadding, AlertDialog theDialog) { this.originalBottomPadding = originalBottomPadding; this.theDialog = theDialog; } public void onClick(View view) { performValidation(); } public void performValidation() { getEditText().setError(null); if (editTextValidator.testValidity()) { // Dismiss once everything is OK. theDialog.dismiss(); ValidatingEditTextPreference.this.onClick(theDialog, AlertDialog.BUTTON_POSITIVE); // reset padding - for when dialog is used again if (originalBottomPadding != Integer.MIN_VALUE) { LinearLayout parentLayout = (LinearLayout) getEditText() .getParent(); if (originalBottomPadding == parentLayout .getPaddingBottom()) { parentLayout.setPadding(parentLayout.getPaddingLeft(), parentLayout.getPaddingTop(), parentLayout.getPaddingRight(), originalBottomPadding); } } } else { // increase padding so error message doesn't cover buttons if (originalBottomPadding != Integer.MIN_VALUE) { LinearLayout parentLayout = (LinearLayout) getEditText() .getParent(); if (originalBottomPadding == parentLayout .getPaddingBottom()) { parentLayout .setPadding( parentLayout.getPaddingLeft(), parentLayout.getPaddingTop(), parentLayout.getPaddingRight(), (int) (parentLayout.getPaddingBottom() + getEditText() .getHeight() * 1.05)); } } // don't dismiss the dialog } } private final int originalBottomPadding; private final AlertDialog theDialog; @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { performValidation(); return true; } } private EditTextValidator editTextValidator; }