35

Some, but not all, devices running Jelly Bean (4.2.1) appear to be missing the exclamation point error icon that should appear on a TextView (or, more commonly, an EditText) that has an error set on it via TextView.setError(CharSequence error).

enter image description here enter image description here

The Galaxy Nexus definitely seems to be missing the icon.

The effect is that the error status set by setError is only apparent when the EditText has focus. This makes setError(...) much less useful as it's often used to encourage users to return to that EditText to fix a problem. E.g., you have a standard login screen with username and password form entries that are validated when the user clicks a submit button. A validation error message set on the username form won't display unless the user clicks back to that form -- which is what the error icon is designed to encourage them to do!

To test: (There may be a more readily accessible EditText, but this one is very widely available)

  1. Open Settings
  2. Select 'Add account' (this is in 'Accounts and Sync' on older devices)
  3. Select 'Google' as the account type
  4. Select 'Existing' (after clicking 'Next' and 'Sign in' on older devices)
  5. Leaving the 'Email' EditText blank, click on the 'Password' EditText

At this point, an error is set on the 'Email' EditText saying that it can't be blank. On devices that don't have this problem, the usual error icon is shown, which expands to the full error message when the EditText has focus. On Galaxy Nexuses running Jelly Bean, no icon is shown and the error is only visible at all when the 'Email' EditText has focus again, and still lacks the icon at that point.

This looks like a bug, but I wanted to check if other people can reproduce it, have ideas about what the problem might be, and have a good workaround.

Using setError(CharSequence error, Drawable icon) would probably fix things, but it'd be nice to be able to use the stock error graphic across different Android versions.

blahdiblah
  • 33,069
  • 21
  • 98
  • 152
  • 2
    Oh my God, FINALLY... After 2 hours of trying and searching the internet, I stumble upon this thread. So, obviously, I have the exact same problem, Galaxy Nexus 4.2.1. What I did observe is that (sometimes), after screen orientation change, the icon appears, even if the field doesn't have focus. But only sometimes. I really don't know what to say. But yeah, I do believe this is a bug. – Bogdan Zurac Dec 12 '12 at 15:39
  • @Andrew Tell me about it. I spent ages trying to figure out what was wrong with my error display logic before I realized that the icon was **never** showing up. – blahdiblah Dec 12 '12 at 16:55
  • It happens the same to me...was looking for this bug on Google, and after 20 minutes I've found this... I've tested the same activity on 4.1.1 and works OK, they put that bug on 4.2 – noni Dec 14 '12 at 20:49
  • 1
    For completeness here is the official bug listing: http://code.google.com/p/android/issues/detail?id=40417 Looks like it'll be fixed in a future release. – Charles Harley Dec 28 '12 at 22:51
  • In the meantime, it is possible to use a workaround. – Oleg Vaskevich Jan 05 '13 at 19:42
  • 2
    This appears to have been fixed in 4.2.2 – SoftWyer Feb 16 '13 at 16:22
  • Yes, this is fixed in 4.2.2, just tested on the Nexus 7. Finally. – Bogdan Zurac Feb 22 '13 at 12:07
  • How did you changed the color from black to grey of setError() ?? – Rahul Dec 09 '15 at 10:23

2 Answers2

18

Temporary Solution! EditTextErrorFixed.java

While this is indeed an SDK bug, I've managed to use reflection methods to get the icon to work as intended. I checked that it works with both 4.2 and 4.2.1 and verified that it works on my updated Galaxy Nexus.

The source can be found here.

The screenshot shows that the icon on the bottom EditTextErrorFixed persists even if the focus changes. In addition it incorporates another fix where if the user presses Delete on an already empty EditText the error disappears (another bug?).

Demo image

For convenience, here is the EditTextErrorFixed source; the class can easily be used in XML:

package com.olegsv.showerrorfixeddemo;

import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.widget.EditText;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * EditText which addresses issues with the error icon
 * (http://stackoverflow.com/q/13756978/832776) and also the error icon
 * disappearing on pressing delete in an empty EditText
 */
public class EditTextErrorFixed extends EditText {
    public EditTextErrorFixed(Context context) {
        super(context);
    }

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

    public EditTextErrorFixed(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * Don't send delete key so edit text doesn't capture it and close error
     */
    @Override
    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
        if (TextUtils.isEmpty(getText().toString()) && keyCode == KeyEvent.KEYCODE_DEL)
            return true;
        else
            return super.onKeyPreIme(keyCode, event);
    }

    /**
     * Keep track of which icon we used last
     */
    private Drawable lastErrorIcon = null;

    /**
     * Resolve an issue where the error icon is hidden under some cases in JB
     * due to a bug http://code.google.com/p/android/issues/detail?id=40417
     */
    @Override
    public void setError(CharSequence error, Drawable icon) {
        super.setError(error, icon);
        lastErrorIcon = icon;

        // if the error is not null, and we are in JB, force
        // the error to show
        if (error != null /* !isFocused() && */) {
            showErrorIconHax(icon);
        }
    }

    /**
     * In onFocusChanged() we also have to reshow the error icon as the Editor
     * hides it. Because Editor is a hidden class we need to cache the last used
     * icon and use that
     */
    @Override
    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
        super.onFocusChanged(focused, direction, previouslyFocusedRect);
        showErrorIconHax(lastErrorIcon);
    }

    /**
     * Use reflection to force the error icon to show. Dirty but resolves the
     * issue in 4.2
     */
    private void showErrorIconHax(Drawable icon) {
        if (icon == null)
            return;

        // only for JB 4.2 and 4.2.1
        if (android.os.Build.VERSION.SDK_INT != Build.VERSION_CODES.JELLY_BEAN &&
                android.os.Build.VERSION.SDK_INT != Build.VERSION_CODES.JELLY_BEAN_MR1)
            return;

        try {
            Class<?> textview = Class.forName("android.widget.TextView");
            Field tEditor = textview.getDeclaredField("mEditor");
            tEditor.setAccessible(true);
            Class<?> editor = Class.forName("android.widget.Editor");
            Method privateShowError = editor.getDeclaredMethod("setErrorIcon", Drawable.class);
            privateShowError.setAccessible(true);
            privateShowError.invoke(tEditor.get(this), icon);
        } catch (Exception e) {
            // e.printStackTrace(); // oh well, we tried
        }
    }
}
Constantinius
  • 34,183
  • 8
  • 77
  • 85
Oleg Vaskevich
  • 12,444
  • 6
  • 63
  • 80
0

I know there is a solution already here. Its just i try to avoid reflection at all costs on Android. If your ok with reflection go for it but try out my solution below first as it might fix the issue without having to subclass and reflect.

Drawable d= getResources().getDrawable(R.drawable.ic_launcher);
            d.setBounds(0, 0, 
                    d.getIntrinsicWidth(), d.getIntrinsicHeight());

            et.setError("my error",d);
j2emanue
  • 60,549
  • 65
  • 286
  • 456
  • I tried this method. It does not work on Samsung Galaxy 4.2.1 - the exact same device the OP complains about. – Boris Strandjev Sep 03 '17 at 07:31
  • its so long i dont remember anymore. but recently i used the support page for getDrawable (contextCompat ) along with support package for editText wrapped in a inputtextlayout and i have not seen the issue appear . hope that helps. – j2emanue Sep 03 '17 at 12:15
  • I am using support EditText and am able to construct drawable. Still the problem persists on Jelly bean Galaxy Nexus. I used an adaptation of the accepted answer - this one worked for me. – Boris Strandjev Sep 03 '17 at 12:44