There is iOS US2FormValidator library for user input validation (see the picture below). I think that library is better than the default of just popping an alert when something doesn't validate.
I'm looking for how to do such things on Android. Are there some Android analogs of US2FormValidator?
The pop-up effect you have shown on your screenshot can be achieved using Android's built-in setError(String) method on EditText widgets.
Also, you can leverage the power of annotations using the Android Saripaar library that I've authored.
first add the library:
compile 'com.mobsandgeeks:android-saripaar:2.0.2'
The library is very simple to use. In your activity annotate the View references you would like to validate as in the following example.
#Order(1)
private EditText fieldEditText;
#Order(2)
#Checked(message = "You must agree to the terms.")
private CheckBox iAgreeCheckBox;
#Order(3)
#Length(min = 3, message = "Enter atleast 3 characters.")
#Pattern(regex = "[A-Za-z]+", message = "Should contain only alphabets")
private TextView regexTextView;
#Order(4)
#Password(min = 6, scheme = Password.Scheme.ALPHA_NUMERIC_MIXED_CASE_SYMBOLS)
private EditText passwordEditText;
#Order(5)
#ConfirmPassword
private EditText confirmPasswordEditText;
The order attribute specifies the order in which the fields have to be validated.
In your onCreate() method instantiate a new Validator object. and call validator.validate() inside any of your event listeners.
You'll receive callbacks on onSuccess and onFailure methods of the ValidationListener.
If you want to show a pop-up as show in the image above then do the following,
public void onValidationFailed(View failedView, Rule<?> failedRule) {
if (failedView instanceof Checkable) {
Toast.makeText(this, failedRule.getFailureMessage(), Toast.LENGTH_SHORT).show();
} else if (failedView instanceof TextView) {
TextView view = (TextView) failedView;
view.requestFocus();
view.setError(failedRule.getFailureMessage());
}
}
Android has extremely easy-to-use built-in validation mechanism which is great enough. See the following link:
http://blog.donnfelker.com/2011/11/23/android-validation-with-edittext/
I've just come across ValidationKomensky that you may find useful
https://github.com/inmite/android-validation-komensky
Related
I have a number of EditText in an Activity. On clicking the submit button, I want to validate them, and prevent submission if there are errors in those EditText objects. I don't want to use TextWatcher because I don't want the methods to get fired at every single change. It does not make sense for an overall validation before submission. Is there a method that lets us loop through an array of the controls of the form? Thanks.
You have two options:
1) Create a Utils class with static methods for ensuring that the fields are valid.
i.e. toy example for checking email
public class Utils{
public static boolean isValidEmail(String str){
return str.contains("#");
}
}
and do so for checking the various fields (phone #, email, name, etc...). In your Activity that has the EditText(s), when you try to submit them, have something like:
public boolean validateFields(){
boolean result = true;
if(!Utils.isValidEmail(mEmailEdit.getText().toString()){
mEmailEdit.setError("Invalid email!");
result = false;
}
if(!Utils.isValidName(mEmailEdit.getText().toString()){
mNameEdit.setError("Invalid name!");
result = false;
}
return result;
}
This is a very simple idea of what you would do. Call validateFields() when clicking the submit button, and if the validateFields() method returns false, then do not proceed with the fields. If it returns true, well then all fields are valid and call another method to submit the data to w/e you are using it for.
2) (Best option for larger projects) Create an interface, call it Validator with a boolean-return function called validate(). This validator interface is extended for each various validation you wish to do, and you create a new interface like so:
public interface Validator{
public boolean validate(String s);
}
public interface EmailValidator extends Validator{
#Override
public boolean validate(String s){
return s.contains("#");
}
}
And extend a new EditText class view that has a Validator interface field, with a getter/setter. Then, in the validateFields() method, we do the same thing except call each EditText's validation interface's validate() method. There are a few more subtleties for this and I can type this all out if interested on how to do exactly. Let me know if that helps
The most straight forward way to do this is to get references to each of your sub views after you create the main view via setContentView(..). Use findViewById() to get references to each of them.
Then in your submit button click handler grab the inputs from each of them via something like nameField.getText() and do whatever validation you want. And if it fails show the error to the user in some fashion.
So, taking ideas from Lucas, creating custom components such as a DateEditText extending EditText and implementing a Validator interface, in my activity button for update onclick, I call this method that I wrote "isValidViewGroup(ViewGroup viewGroup), it will recursively go through all views, starting with the given viewGroup, and check children views, until it meets one implementing Validator and then call its isValid() method. It stops as soon as it finds an invalid one, or go through the end of views. Here's the method:
...
private boolean isValidViewGroup(ViewGroup viewGroup) {
int viewGroupChildCount = viewGroup.getChildCount();
View view = null;
for (int i = 0; i < viewGroupChildCount;i++) {
view = viewGroup.getChildAt(i);
if (view instanceof ViewGroup){
if (!isValidViewGroup((ViewGroup) view)){
return false;
}
} else {
if (view instanceof Validator){
if (!((Validator)view).isValid()){
return false;
}
}
}
}
return true;
}
...
I'm sure there could be a better, more efficient way, but for the moment that works really fine.
Ok - preface with I am new to android and new to java as well. But I did code in a previous lifetime.....
I am working on an application and now trying to pull some methods out and place into a utility class. In particular, I have a method which updates text views that I wanted to move out of an activity.
When in the activity, I had two versions of the method the only difference being that one would accept a view in the parameter list (I used this to populate some fields in a custom dialog). They all worked fine.
Once placed in the external utility package/class, the method no longer works - no errors, and it appears to have all it needs - I've done some logging and the view claims to be visible and the textview ids appear to be correct. Yet nothing changes on the screen.
I'm guessing this is something completely obvious and stupid but I can't seem to sort it out.
package xxx.xxx.Utility;
(some imports)
public class Utility {
public static void updateTextView(int id, String opt_data, View v) {
String TAG = "updateTextView: ";
if (v.getVisibility() == View.VISIBLE) Log.i(TAG," visible");
TextView tvTarget = (TextView) v.findViewById(id);
if (tvTarget == null) {
Log.i(TAG, "Error: updateTextView target is null");
}
if (opt_data != null) {
if (tvTarget != null) {
tvTarget.setText(opt_data);
}
} else {
if (tvTarget != null) {
tvTarget.setText(" ");
}
}
}
}
EDIT w/ Additional Info:
In the inital description I mentioned that this method was also being used to populate some fields of a pop-up dialog with data. In fact, I can request any number of dialogs in that manner and they all display properly and with the correct (and different) data. So it seems to fail only when trying to update the tv data of the main activity (the initial) view.
I'm guessing this is something completely obvious and stupid but I
can't seem to sort it out.
It helps to get the root(?) parent (?) view properly. IE,
currentView = this.findViewById(android.R.id.content).getRootView();
and now all is well.
Is it possible for the uiautomator to select a password EditText? I have no problem finding other EditText views by their android:hint property, but the uiautomatorviewer shows all password fields as NAF. I tried setting the password field content description and that didn't work either.
If it's not possible, how do you set a timeout for a tester to manually enter a password?
I had the same problem with API v16.
Today I tried my script with v17 (Android 4.2) and it worked like a charm.
It seems that the first version of uiautomator has some major bugs.
Here is my code:
// click the admin button
new UiObject(new UiSelector().text("admin")).click();
// set pwd text
new UiObject(new UiSelector().description("pwdEditText")).setText("admin");
// click login button
new UiObject(new UiSelector().description("loginButton")).click();
Sometimes, your Views won't have a ResourceId, such as the case where you need to programmatically type into a text field within a webpage rendered inside a WebView. i.e.
// Fetch the EditText within the iOrder Webpage.
final UiObject lUiObject = UiDevice.getInstance(getInstrumentation()).findObject(new UiSelector().className(EditText.class).textContains("Enter Loyalty Code"));
In such cases, we need to use the UiSelector class to dynamically search for the EditText; however, you'll find that the returned Matcher<View> isn't compatible with the onView(with(...)) methods.
When using the UiSelector, you can take advantage of a UiDevice reference to programmatically fake key presses using the approach below:
/* Declare the KeyCodeMap. */
private static final KeyCharacterMap MAP_KEYCODE = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
/** Simulates typing within a UiObject. The typed text is appended to the Object. */
private final void type(final UiObject pUiObject, final String pString, final boolean pIsSimulateTyping, final boolean pIsClearField) throws Exception {
// Fetch the Instrumentation.
final Instrumentation lInstrumentation = getInstrumentation();
// Fetch the UiDevice.
final UiDevice lUiDevice = UiDevice.getInstance(lInstrumentation);
// Are we clearing the Field beforehand?
if(pIsClearField) {
// Reset the Field Text.
pUiObject.setText("");
}
// Are we going to simulate mechanical typing?
if(pIsSimulateTyping) {
// Click the Field. (Implicitly open Android's Soft Keyboard.)
pUiObject.click();
// Fetch the KeyEvents.
final KeyEvent[] lKeyEvents = SignUpTest.MAP_KEYCODE.getEvents(pString.toCharArray());
// Delay.
lInstrumentation.waitForIdleSync();
// Iterate the KeyEvents.
for(final KeyEvent lKeyEvent : lKeyEvents) {
// Is the KeyEvent a Release. (The KeyEvents contain both down and up events, whereas `pressKeyCode` encapsulates both down and up. This conditional statement essentially decimates the array.)
if(lKeyEvent.getAction() == KeyEvent.ACTION_UP) {
// Press the KeyEvent's corresponding KeyCode (Take account for special characters).
lUiDevice.pressKeyCode(lKeyEvent.getKeyCode(), lKeyEvent.isShiftPressed() ? KeyEvent.META_SHIFT_ON : 0);
// Delay.
lInstrumentation.waitForIdleSync();
}
}
// Close the keyboard.
lUiDevice.pressBack();
}
else {
// Write the String.
pUiObject.setText(pUiObject.getText() + pString);
}
// Delay.
lInstrumentation.waitForIdleSync();
}
I just find them by id:
onView(withId(R.id.input_password)).perform(typeText("password"));
I see that the UI Automator Viewer now also shows the resource-id property, which would be useful if you don't have access to the code.
I have a PreferenceScreen in which the user is capable, if system can't autodetect it, to enter the device's phone number. I'm still learning this part of Android but I managed to understand a bit of PreferenceScreens by examples provided by Android SDK itself and a few tutorials.
What I want is that the user can save the phone number only if null or valid, where by "valid" I mean running a generic validation logic (ie. an anonymous method that returns true or false, that can be reused in any possible situation*) or better, just to simplify things, ^(\+39)?3[0-9]{9}$
For now I have the following XML snip
<EditTextPreference
android:inputType="phone"
android:key="#string/preference_phoneNo"
android:selectAllOnFocus="true"
android:singleLine="true"
android:summary="#string/pref_phoneNumber_description"
android:title="#string/pref_phoneNumber" />
and following code by courtesy of Eclipse New Activity wizard:
private void setupSimplePreferencesScreen() {
if (!isSimplePreferences(this)) {
return;
}
addPreferencesFromResource(R.xml.pref_general);
bindPreferenceSummaryToValue(findPreference(getString(R.string.preference_phoneNo)));
}
addPreferenceFromResource is supposed to load the XML node and add the preference to the screen, while binPreferenceSummaryToValue is supposed to make description text change when preference is updated. Just for sake of completeness for those who don't like code courtesy of the IDE, the second method is provided by Eclipse who also provides a private class in the code file that is
/**
* A preference value change listener that updates the preference's summary
* to reflect its new value.
*/
In the general case, what should I do to perform validation logic before the preference gets saved when I click OK on the preference editor? Where is the validation logic to be put in a PreferenceScreen?
*Aren't we all here to learn?
Android has a built in helper method for this.
String phoneNumber = ...;
boolean valid = PhoneNumberUtils.isGlobalPhoneNumber(phoneNumber);
For a generic, re-usable method, here's the implementation of that method in PhoneNumberUtils, courtesy of AOSP (Apache licensed)
private static final Pattern GLOBAL_PHONE_NUMBER_PATTERN =
Pattern.compile("[\\+]?[0-9.-]+");
...
public static boolean isGlobalPhoneNumber(String phoneNumber) {
if (TextUtils.isEmpty(phoneNumber)) {
return false;
}
Matcher match = GLOBAL_PHONE_NUMBER_PATTERN.matcher(phoneNumber);
return match.matches();
}
Validation should occur within a Preference.OnPreferenceChangeListener , in the onPreferenceChange method. Simply return false if you don't want the value to be saved.
Example snippet:
private static Preference.OnPreferenceChangeListener myListener =
new Preference.OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object value) {
String stringValue = value.toString();
if (preference instanceof PhoneNumberPreference) {
return isGlobalPhoneNumber(value);
}
}
...
As a note, since you're starting off with the Settings activity generated by the Eclipse wizard, this listener has already been built for you. You just need to edit it to include validation of the phone number (assuming that's what's being edited), and to return false if the number is invalid, so it won't be saved to preferences.
in my android application at some event in an activity I want to ask the user for a name (string). I know how to do this: call showDialog, create the dialog in the Activity.onCreateDialog method (I need to supply a string for the label) and handle the result in the onClick of the dialog. This works fine and to my satisfaction.
BUT this way I have three different places, where this simple task spreads throughout the code of my activity. I would much more prefer to keep this code together, to write some code like this:
string result;
if (showSimpleEditDialog(idForLabelString, result)==DIALOG_OK)
{
// do something with the result
}
or maybe with a class instance
SimpleEditDialog dlg = new SimpleEditDialog(idForLabelString);
if (dlg.showModal()==DIALOG_OK)
{
string result = dgl.getResult();
// do something with the result
}
(The "idForLabelString" would be some resource id for the label to use, DIALOG_OK would be some constant returned when the user clicks OK)
I know, I would have to write this methodes or this class. But for better readibility of my code I would do it. Any suggestions?
Thank you,
Gerhard
"BUT this way I have three different places, where this simple task spreads throughout the code"
So why don't you create a Method for this task? What you are talking about sounds like some sort of 'ActionListener' to me. This can be done in Java/Swing, but not in Android.
But, if you have three Dialogs, which all need to do the same when "YES" e.g. "NO" is pressed, you could define the 'DialogInterface.OnClickListener()' as a global inner-Class (or in a second class which extends the 'onClickListener') and then use it for all the Dialogs.
Now actually the problem with modal dialogs is mostly a problem with programm flow. You want to keep things together that belong together. You want to display a dialog that returns "ok" or "cancel" and additionaly e.g. a string that the user entered into one of the dialog widgets.
I do not want to write half of the code up to the line where I need the result of the dialog on one place and the rest of the code on another place namely the onClickListener of the dialog.
In some scenarios the first dialog might invoke a second dialog e.g. to specify a color which is not in the list of the first dialog's ListView.
Your code will be scattered all over the place (in each dialog's button onClickListener) and will be hard to read or to maintain.
Now after having written some unclear code like that I came up with the following solution which certainly respects the android design guides.
Instead of directly showing a dialog I create a Handler derived class which handles messages.
I send it a first message which creates and shows a dialog. It also forwards the handler to the dialog and the diaolg in it's onStop method sends another message to the handler, indicating the end of the dialog. There you can examine the dialogs properties, the contents of the edit fields or whether it was stopped with OK or CANCEL.
Now in the message handler all the logic of the task sits in different cases of the messages arg1 value.
Some cases might be skipped (e.g. the user selected a standard color and did not need a special color dialog).
The dialogs are independant of the scenario from which they are called and in their code only reflect their simple task (selecting from a list, some checkboxes etc.). They may be reused from other scenarios.
Following a kind of a template how to use this approach:
public class DoSomethingWithDialogs extends Handler
{
Context context; // from which it was called
final static int stepBegin = 0;
final static int stepNext = 1;
final static int stepSomethingElse = 2;
final static int stepLast = 3;
protected DoSomethingWithDialogs(Context context)
{
this.context = context;
}
public static void start(Context context)
{ // this is the main (only) entry point from outside
DoSomethingWithDialogs st = new DoSomethingWithDialogs(context);
st.sendMessage(st.obtainMessage(0, stepBegin, 0));
}
#Override
public void handleMessage(Message msg)
{
// step by step handling the task
switch (msg.arg1)
{
case stepBegin:
{
SomeDlg somedlg = new SomeDlg(context, this, stepNext);
// when the dialog closes, it sends a message to this with stepNext as arg1
somedlg.show();
}
break;
case stepNext:
{ // this message was send by the dialog when it finished
SomeDlg somedlg = (SomeDlg) msg.obj;
if (msg.arg2 == Dialog.BUTTON_NEGATIVE)
{
// has been canceled, nothing to do
} else
{
if (somedlg.someProperty)
{
} else
{
sendMessage(obtainMessage(0, stepSomethingElse, 0));
}
}
}
break;
case stepSomethingElse:
break;
}
}
}