I want to create an EditText which accepts passwords. I want to hide the character as soon as it is typed. So, I used a TransformationMethod.
I am new to this so, I tried the following code.
EditText editText = (EditText) findViewById(R.id.editText);
editText.setTransformationMethod(new PasswordTransformationMethod());
private class PasswordTransformationMethod extends Transformation implements TransformationMethod {
#Override
public CharSequence getTransformation(CharSequence source, View view) {
return "/";
}
#Override
public void onFocusChanged(View view, CharSequence source, boolean focused, int direction, Rect previouslyFocusedRect) {
source = getTransformation(source, view);
}
}
However, it throws,
01-03 10:22:35.750: E/AndroidRuntime(2102): java.lang.IndexOutOfBoundsException
I am missing something. Any help will be appreciated.
The above method has lots of errors.
So, I am sharing the code that I use to convert passwords into dots.
Create a separate class in the same Java file like this,
public class MyPasswordTransformationMethod extends PasswordTransformationMethod {
#Override
public CharSequence getTransformation(CharSequence source, View view) {
return new PasswordCharSequence(source);
}
private class PasswordCharSequence implements CharSequence {
private CharSequence mSource;
public PasswordCharSequence(CharSequence source) {
mSource = source;
}
public char charAt(int index) {
return '.';
}
public int length() {
return mSource.length();
}
public CharSequence subSequence(int start, int end) {
return mSource.subSequence(start, end); // Return default
}
}
};
The implementation goes like this,
passwordEditText = (EditText) findViewById(R.id.passwordEditText);
passwordEditText.setTransformationMethod(new MyPasswordTransformationMethod());
Related
Moving from MVP to MVVM and trying to learn from tutorials on web.
Some of the tutorials state that ViewModel classes should not have any reference to Activity or View(android.view.View) classes.
But in some of the tutorials i've seen Views are used in ViewModel class and Activities to start other Activities using ViewModel.
For example:
import android.arch.lifecycle.ViewModel;
import android.support.annotation.NonNull;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import com.journaldev.androidmvvmbasics.interfaces.LoginResultCallback;
import com.journaldev.androidmvvmbasics.model.User;
public class LoginViewModel extends ViewModel {
private User user;
private LoginResultCallback mDataListener;
LoginViewModel(#NonNull final LoginResultCallback loginDataListener) {
mDataListener = loginDataListener;
user = new User("", "");
}
public TextWatcher getEmailTextWatcher() {
return new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
user.setEmail(editable.toString());
}
};
}
public TextWatcher getPasswordTextWatcher() {
return new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
user.setPassword(editable.toString());
}
};
}
public void onLoginClicked(#NonNull final View view) {
checkDataValidity();
}
private void checkDataValidity() {
if (user.isInputDataValid())
mDataListener.onSuccess("Login was successful");
else {
mDataListener.onError("Email or Password not valid");
}
}
}
Another one with View.OnClickListener
public class PostViewModel extends BaseObservable {
private Context context;
private Post post;
private Boolean isUserPosts;
public PostViewModel(Context context, Post post, boolean isUserPosts) {
this.context = context;
this.post = post;
this.isUserPosts = isUserPosts;
}
public String getPostScore() {
return String.valueOf(post.score) + context.getString(R.string.story_points);
}
public String getPostTitle() {
return post.title;
}
public Spannable getPostAuthor() {
String author = context.getString(R.string.text_post_author, post.by);
SpannableString content = new SpannableString(author);
int index = author.indexOf(post.by);
if (!isUserPosts) content.setSpan(new UnderlineSpan(), index, post.by.length() + index, 0);
return content;
}
public int getCommentsVisibility() {
return post.postType == Post.PostType.STORY && post.kids == null ? View.GONE : View.VISIBLE;
}
public View.OnClickListener onClickPost() {
return new View.OnClickListener() {
#Override
public void onClick(View v) {
Post.PostType postType = post.postType;
if (postType == Post.PostType.JOB || postType == Post.PostType.STORY) {
launchStoryActivity();
} else if (postType == Post.PostType.ASK) {
launchCommentsActivity();
}
}
};
}
public View.OnClickListener onClickAuthor() {
return new View.OnClickListener() {
#Override
public void onClick(View v) {
context.startActivity(UserActivity.getStartIntent(context, post.by));
}
};
}
public View.OnClickListener onClickComments() {
return new View.OnClickListener() {
#Override
public void onClick(View v) {
launchCommentsActivity();
}
};
}
private void launchStoryActivity() {
context.startActivity(ViewStoryActivity.getStartIntent(context, post));
}
private void launchCommentsActivity() {
context.startActivity(CommentsActivity.getStartIntent(context, post));
}
}
Another one with Activity Reference
public class UserProfileViewModel {
/* ------------------------------ Constructor */
private Activity activity;
/* ------------------------------ Constructor */
UserProfileViewModel(#NonNull Activity activity) {
this.activity = activity;
}
/* ------------------------------ Main method */
/**
* On profile image clicked
*
* #param userName name of user
*/
public void onProfileImageClicked(#NonNull String userName) {
Bundle bundle = new Bundle();
bundle.putString("USERNAME", userName);
Intent intent = new Intent(activity, UserDetailActivity.class);
intent.putExtras(bundle);
activity.startActivity(intent);
}
/**
* #param editable editable
* #param userProfileModel the model of user profile
*/
public void userNameTextChange(#NonNull Editable editable,
#NonNull UserProfileModel userProfileModel) {
userProfileModel.setUserName(editable.toString());
Log.e("ViewModel", userProfileModel.getUserName());
}
}
Is it okay for ViewModel class to contain Android and View classes,
isn't this bad for unit testing?
Which class should a custom view model class extend? ViewModel or
BaseObservable/Observable?
Is there any tutorial link that shows simple usage of MVVM and with
only focus on architecture without any Dagger2, LiveData, or RxJava
extensions? I'm only looking for MVVM tutorials for now.
From the documentation:
Caution: A ViewModel must never reference a view, Lifecycle, or any class that may hold a reference to the activity context.
This is because a ViewModel survives configuration changes. Let's say you have an activity and you rotate the device. The activity is killed and a new instance is created. If you put views in the viewmodel, then the activity won't be garbage collected because the views hold the reference to the previous activity. Also, the views themselves will be recreated but you're keeping old views in the viewmodel. Basically don't put any views, context, activity in the viewmodel.
Here's a sample from google: https://github.com/googlesamples/android-sunflower/
I am trying to write a Unit Test for a validator of my android Application. The validator accepts as parameter EditText, therefore I need to mock it. However the mocking does not work, forcing the Test to crash on calling the when() method with the exception:
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.
My code is:
#RunWith(MockitoJUnitRunner.class)
public class MyUnitTest
{
#Mock
Context mMockContext;
#Test
public void validateIsCorrect() {
final EditText input = Mockito.mock(EditText.class);
when(input.getText()).thenReturn(Editable.Factory.getInstance().newEditable("123"));
...
}
}
The dependencies in build.gradle file are:
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:1.10.19'
The method getText() of the EditText is not private or final. What am I doing wrong? Is it possible to mock an EditText this way? How?
When you're running a unit test, you're using a standard JVM context, not Android's context and that's why it's crashing: The Editable.Factory class and it's methods (like getInstance()) are not in the classpath. And they have not been mocked either.
What I'd do is to create a class that implements Editable with a private member to hold a string reference and use it to mock the getText() method.
Something like this:
class MockEditable implements Editable {
private String str;
public MockEditable(String str) {
this.str = str;
}
#Override #NonNull
public String toString() {
return str;
}
#Override
public int length() {
return str.length();
}
#Override
public char charAt(int i) {
return str.charAt(i);
}
#Override
public CharSequence subSequence(int i, int i1) {
return str.subSequence(i, i1);
}
#Override
public Editable replace(int i, int i1, CharSequence charSequence, int i2, int i3) {
return this;
}
#Override
public Editable replace(int i, int i1, CharSequence charSequence) {
return this;
}
#Override
public Editable insert(int i, CharSequence charSequence, int i1, int i2) {
return this;
}
#Override
public Editable insert(int i, CharSequence charSequence) {
return this;
}
#Override
public Editable delete(int i, int i1) {
return this;
}
#Override
public Editable append(CharSequence charSequence) {
return this;
}
#Override
public Editable append(CharSequence charSequence, int i, int i1) {
return this;
}
#Override
public Editable append(char c) {
return this;
}
#Override
public void clear() {
}
#Override
public void clearSpans() {
}
#Override
public void setFilters(InputFilter[] inputFilters) {
}
#Override
public InputFilter[] getFilters() {
return new InputFilter[0];
}
#Override
public void getChars(int i, int i1, char[] chars, int i2) {
}
#Override
public void setSpan(Object o, int i, int i1, int i2) {
}
#Override
public void removeSpan(Object o) {
}
#Override
public <T> T[] getSpans(int i, int i1, Class<T> aClass) {
return null;
}
#Override
public int getSpanStart(Object o) {
return 0;
}
#Override
public int getSpanEnd(Object o) {
return 0;
}
#Override
public int getSpanFlags(Object o) {
return 0;
}
#Override
public int nextSpanTransition(int i, int i1, Class aClass) {
return 0;
}
}
You can then make use of this class
Mockito.when(input.getText()).thenReturn(new MockEditable("123"));
Looking at this from a bit further away; I am asking myself: why does your validator need to know anything about Android specific classes?
What I mean is: I assume that your validator (in the end) has to check the properties of maybe a String, or something alike?
I would thus suggest to focus on separating concerns here:
Create a component that fetches a String from your EditText
Create a validator that works with such strings
Then you don't need any specific mocking for your validator in the first place!
final EditText editText = Mockito.mock(EditText.class);
final ArgumentCaptor<Editable> captor = ArgumentCaptor.forClass(Editable.class);
Mockito.doNothing().when(editText).setText(captor.capture());
Mockito.when(editText.getText()).thenAnswer(new Answer<Object>() {
#Override
public Object answer(InvocationOnMock invocation) {
return captor.getValue();
}
});
What about this guys, it works for me:
Please don't forget to add the MockitoAnnotations.init(this); and also use
#Mock private EditTextView passwordField;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
when(rootView.findViewById(R.id.button_logout)).thenReturn(buttonLogout);
when(rootView.findViewById(R.id.button_unlock)).thenReturn(buttonUnlock);
when(rootView.findViewById(R.id.ScreenLock_PasswordTextField)).thenReturn(passwordField);
when(passwordField.getText()).thenReturn(Editable.Factory.getInstance().newEditable("asd"));
when(application.getPassword()).thenReturn("asd");
sut = new ScreenLockPresenterImpl(application, rootView, screenLockListener,
logoutButtonClickListener);
}
#Test
public void testOnClickWhenOk() {
sut.onClick(null);
verify(passwordField).getText();
verify(screenLockListener).unLock();
}
I think this is what you are looking for:
when(passwordField.getText()).thenReturn(Editable.Factory.getInstance().newEditable("asd"));
I need to create custom bullet for password for editText and put some padding between bullet symbols.
Is there some way to do this?
For changing the character that is displayed you can call the method setTransformationMethod (TransformationMethod method) and pass it a custom PasswordTransformationMethod.
This could look something like the following:
public class AsteriskPasswordTransformationMethod extends PasswordTransformationMethod {
#Override
public CharSequence getTransformation(CharSequence source, View view) {
return new PasswordCharSequence(source);
}
private class PasswordCharSequence implements CharSequence {
private CharSequence mSource;
public PasswordCharSequence(CharSequence source) {
mSource = source; // Store char sequence
}
public char charAt(int index) {
return '*'; // This is the important part
}
public int length() {
return mSource.length(); // Return default
}
public CharSequence subSequence(int start, int end) {
return mSource.subSequence(start, end); // Return default
}
}
};
and then set it like this:
textView.setTransformationMethod(new AsteriskPasswordTransformationMethod());
For changing the padding and such you should use either use textScaleX or if you are at API Level 21+ use letterSpacing in the XML.
I have a EditText which is a password field. By default android has its (.) dot which i want to replace with some image dot. How can I do that any suggestions.
You can try the PasswordTransformationMethod Class Check this Link
public class MyPasswordTransformationMethod extends PasswordTransformationMethod {
#Override
public CharSequence getTransformation(CharSequence source, View view) {
return new PasswordCharSequence(source);
}
private class PasswordCharSequence implements CharSequence {
private CharSequence mSource;
public PasswordCharSequence(CharSequence source) {
mSource = source; // Store char sequence
}
public char charAt(int index) {
return '*'; // This is the important part
}
public int length() {
return mSource.length(); // Return default
}
public CharSequence subSequence(int start, int end) {
return mSource.subSequence(start, end); // Return default
}
}
};
// Call the above class using this:
text.setTransformationMethod(new MyPasswordTransformationMethod());
Is there any way to change the password text from dot(.) to asterisk(*) .
Password is entering in edittext.
<EditText
android:id="#+id/passWord1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:inputType="number"
android:password="true"/>
Insert edittext in your xml file,
<EditText
android:id="#+id/passWordEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:inputType="textPassword"/>
and your class file go on and get findViewById from edittext and implement for this,
EditText edittext = (EditText)findViewById(R.id.passWordEditText);
edittext.setTransformationMethod(new AsteriskPasswordTransformationMethod());
and This class implement for that,
public class AsteriskPasswordTransformationMethod extends PasswordTransformationMethod {
#Override
public CharSequence getTransformation(CharSequence source, View view) {
return new PasswordCharSequence(source);
}
private class PasswordCharSequence implements CharSequence {
private CharSequence mSource;
public PasswordCharSequence(CharSequence source) {
mSource = source; // Store char sequence
}
public char charAt(int index) {
return '*'; // This is the important part
}
public int length() {
return mSource.length(); // Return default
}
public CharSequence subSequence(int start, int end) {
return mSource.subSequence(start, end); // Return default
}
}
};
And If your code is Kotlin then you have to make separate java file then you have to use java with kotlin code.
<EditText
android:id="#+id/passWord1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:inputType="textPassword"//here is the change. check it once in your xml
android:password="true"/>
In eclipse there will be hints when you click Ctrl + Space when you move cursor at android:inputType. Then you can see list of options. there you can select textPassword
If you want to see * in place of . then check this Android: Asterisk Password Field
Got answer with help of link posted by Ram kiran
text.setTransformationMethod(new AsteriskPasswordTransformationMethod());
public class AsteriskPasswordTransformationMethod extends PasswordTransformationMethod {
#Override
public CharSequence getTransformation(CharSequence source, View view) {
return new PasswordCharSequence(source);
}
private class PasswordCharSequence implements CharSequence {
private CharSequence mSource;
public PasswordCharSequence(CharSequence source) {
mSource = source; // Store char sequence
}
public char charAt(int index) {
return '*'; // This is the important part
}
public int length() {
return mSource.length(); // Return default
}
public CharSequence subSequence(int start, int end) {
return mSource.subSequence(start, end); // Return default
}
}
};
Kotlin
class AsteriskPasswordTransformationMethod : PasswordTransformationMethod() {
override fun getTransformation(source: CharSequence, view: View): CharSequence {
return PasswordCharSequence(source)
}
inner class PasswordCharSequence (private val source: CharSequence) : CharSequence {
override val length: Int
get() = source.length
override fun get(index: Int): Char = '*'
override fun subSequence(startIndex: Int, endIndex: Int): CharSequence {
return source.subSequence(startIndex, endIndex)
}
}
}
EditText.setTransformationMethod(new PasswordTransformationMethod());
In Kotlin way:
class AsteriskPasswordTransformationMethod: PasswordTransformationMethod() {
override fun getTransformation(source: CharSequence?, view: View?): CharSequence {
return super.getTransformation(source, view)
}
abstract inner class PasswordCharSequence(val source: CharSequence) : CharSequence {
override val length: Int
get() = source.length
override fun get(index: Int): Char =
'*'
override fun subSequence(start: Int, end: Int): CharSequence {
return source.subSequence(start, end) // Return default
}
}
}`
For android:inputType, there is a type of password.
Try this
android:inputType="textPassword"