Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

password Visibility Toggle crash app while upgrade dependency to 27.1.0

Tags:

android

I am getting many crash related to password visibility. One more strange is its crashing on some devices not all.

I have testing in Nokia 5, Samsung note 4 and s7, Honor 5C and 9, Redmi Note 4 and 4, Moto E and G play and moto M all working fine.

JavaCode

    EditText loEtPassword = (EditText) findViewById(R.id.etPassword);
    loEtPassword.setTransformationMethod(new PasswordTransformationMethod()); // Java internal class.
    loEtPassword.setOnEditorActionListener(new DoneOnEditorActionListener(loBtnLogin)); // custom class.

Validation

    public static class LoginUser {
          public String lsEmail, lsPassword, lsIMEINumber, lsJsonParameter;
    }

    LoginUser loLoginUser = new LoginUser();
    loLoginUser.lsEmail = loEtEmail.getText().toString().trim();
    loLoginUser.lsPassword = loEtPassword.getText().toString();

    if (validate(loLoginUser)) {
          //cont...
    }

    private boolean validate(LoginUser foLoginUser) {

          final EditText loEtPassword = (EditText) findViewById(R.id.etPassword);

          boolean lbIsValid = true;

          if (foLoginUser.lsPassword.length() <= 0) {
              loEtPassword.setError("Please enter Password");
              loEtPassword.requestFocus();
              lbIsValid = false;
          }
          return lbIsValid;
      }

XML file

 <android.support.design.widget.TextInputLayout
            android:id="@+id/ilPassword"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textColorHint="@color/textColorGray"
            app:hintEnabled="false"
            app:passwordToggleEnabled="true"
            app:passwordToggleTint="@color/textColorGray">

            <EditText
                android:id="@+id/etPassword"
                style="@style/editTextStyle"
                android:layout_marginBottom="@dimen/MarginBetweenView"
                android:backgroundTint="@color/textColorGray"
                android:drawableLeft="@drawable/ic_password"
                android:drawableStart="@drawable/ic_password"
                android:drawablePadding="@dimen/MarginBetweenInnerView"
                android:hint="@string/HINT_PASSWORD"
                android:imeOptions="actionDone"
                android:inputType="textEmailAddress" />
 </android.support.design.widget.TextInputLayout>

Design

enter image description here

Gradle

apply plugin: 'com.android.application'
apply plugin: 'io.fabric'

android {
    compileSdkVersion 27
    buildToolsVersion "27.0.3"
    defaultConfig {
        applicationId "com.packageName"
        minSdkVersion 14
        targetSdkVersion 25
        multiDexEnabled true
        versionName '7.2'
        versionCode 96
    }
dexOptions {
    javaMaxHeapSize "4g"
    preDexLibraries = false
}
buildTypes {
    release {
        minifyEnabled true
        shrinkResources true
        proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
        }
    }
    productFlavors {
    }
}

dependencies {
    compile files('libs/gcm.jar')
    compile 'com.android.support:support-v4:27.1.0'
    compile 'com.android.support:appcompat-v7:27.1.0'
    compile 'com.android.support:design:27.1.0'
    compile 'com.google.android.gms:play-services-analytics:11.8.0'
    compile('com.crashlytics.sdk.android:crashlytics:2.9.1@aar') {
        transitive = true
    }
    compile 'com.google.firebase:firebase-core:11.8.0'
}

apply plugin: 'com.google.gms.google-services'

Refer snap - got 21 crash from last 24 hours.

enter image description here

Crash log

Caused by java.lang.NullPointerException
Attempt to invoke virtual method 'void android.support.design.widget.CheckableImageButton.setChecked(boolean)' on a null object reference arrow_right
android.support.design.widget.TextInputLayout.passwordVisibilityToggleRequested (Unknown Source:1339)
android.support.design.widget.TextInputLayout.onRestoreInstanceState (Unknown Source:1033)
android.view.View.dispatchRestoreInstanceState (View.java:15777)
android.view.ViewGroup.dispatchRestoreInstanceState (ViewGroup.java:3233)
android.support.design.widget.TextInputLayout.dispatchRestoreInstanceState (Unknown Source:1041)
android.view.ViewGroup.dispatchRestoreInstanceState (ViewGroup.java:3239)
android.view.ViewGroup.dispatchRestoreInstanceState (ViewGroup.java:3239)
android.view.ViewGroup.dispatchRestoreInstanceState (ViewGroup.java:3239)
android.view.ViewGroup.dispatchRestoreInstanceState (ViewGroup.java:3239)
android.view.View.restoreHierarchyState (View.java:15755)
com.android.internal.policy.PhoneWindow.restoreHierarchyState (PhoneWindow.java:2106)
android.app.Activity.onRestoreInstanceState (Activity.java:1098)
android.app.Activity.performRestoreInstanceState (Activity.java:1053)
android.app.Instrumentation.callActivityOnRestoreInstanceState (Instrumentation.java:1175)
android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2714)
android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:2802)
android.app.ActivityThread.-wrap12 (ActivityThread.java)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:1549)
android.os.Handler.dispatchMessage (Handler.java:102)
android.os.Looper.loop (Looper.java:163)
android.app.ActivityThread.main (ActivityThread.java:6361)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:904)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:794)

can anyone help how to prevent this bug?

do i need to upgrade my targetSdkVersion ?

If any alternate solution is there please suggest because if i change the target sdk version then i have to update lots of code in my app.

like image 427
RaRa Avatar asked Apr 04 '18 06:04

RaRa


2 Answers

I solved this by simply changing the inputType of the EditText (or the TextInputEditText in my case) to textPassword. So you should try this:

<EditText
    android:id="@+id/etPassword"
    ...
    android:inputType="textPassword" />

I assume you didn't mean to set it to textEmailAddress.

like image 105
Gumby The Green Avatar answered Oct 01 '22 22:10

Gumby The Green


Since none of the above answers helped me I spent some time on fixing this problem myself. I've found out that crash occurs in my case when orientation changes (maybe there are more cases).

Initially, the solution was kind of ugly using reflection. Extracted the boolean value indicating password visibility and toggled the visibility after orientation change. But later I noticed that even though crash does not appear anymore my solution is not the reason for this crash to be fixed. So I started commenting the code step by step back to find what was actually the so-called solution.

Solution (tested on SDK 26, Samsung Galaxy Tab S3)

The solution was to modify AndroidManifest. Unexpected.

I noticed that adding android:configChanges attribute fixes the problem. Sadly I'm unable to explain exactly how does it fix the problem. The solution was found somewhat accidentally. If orientation value does not fix the problem try different values.

<activity
        android:configChanges="orientation"
        android:name="com.example.activity.LoginActivity"
        android:screenOrientation="sensor" />

The solution for older devices (tested on emulator device, SDK 22)

For older version of SDK I had to extend TextInputLayout in order to fix this problem. Fix with configChanges does not resolve the issue here.

This solution works for new and old devices, so I recommend to stick with it.

import com.google.android.material.textfield.TextInputLayout;

public class PasswordTextInputLayout extends TextInputLayout {
    public PasswordTextInputLayout(Context context) {
        super(context);
    }

    public PasswordTextInputLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public PasswordTextInputLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * We have to change "password visibility toggle enabled"
     * state twice in order to recreate private {@link TextInputLayout#passwordToggleView}.
     * Calling {@link TextInputLayout#setPasswordVisibilityToggleEnabled(boolean)}
     * we also invoke {@link TextInputLayout#updatePasswordToggleView}.
     * Which recreates passwordToggleView if it is equals to null.
     * UI performance is not affected.
     *
     * @param state saved when screen configuration has changed (e.g. orientation change).
     */
    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        setPasswordVisibilityToggleEnabled(false);
        setPasswordVisibilityToggleEnabled(true);
        super.onRestoreInstanceState(state);
    }
}

How to use the last solution

Simple. Instead of tag <com.google.android.material.textfield.TextInputLayout> use <com.example.view.PasswordTextInputLayout>.

<com.example.view.PasswordTextInputLayout
    ... >

    <com.google.android.material.textfield.TextInputEditText
        ...
        />

</com.example.view.PasswordTextInputLayout>

What is the reason for this crash?

Looks like after activity or fragment saves it's state to Bundle (that is savedInstanceState you see in Activity#onCreate) and later uses it to restore the state TextInputLayout fails to do it correctly. passwordToggleView is not restored correctly. A solution for this would be to add in TextInputLayout#onRestoreInstanceState method call updatePasswordToggleView or make appropriate changes to recreate passwordToggleView before it's visibility toggled.

like image 32
Jenea Vranceanu Avatar answered Oct 01 '22 22:10

Jenea Vranceanu