Question

I'm quite new to Android native development, and I'm trying to figure out how to customize the IME action buttons. I've looked at the Google documentation, but I can find very few information about the expected behaviour.

From the offical guide I understand that the keyboard action button can be configured using the attributes:

  • android:imeOptions can set the text/id of the button displayed near the space key to some pre-defined values (E.g. actionGo set the key label to Go and the id to 2)
  • android:imeActionLabel set the label of the button displayed inside the input area when the keyboard is fullscreen, usually in landscape mode. Can be set to any string value.
  • android:imeActionId same as previous but set the numeric Id passed to the callback method

But after some empiric attempts I've found different behaviour between API level 15 and next API levels.

I've set up a simple EditText element with the following attributes:

<EditText
        ...
        android:imeOptions="actionGo"
        android:imeActionLabel="Custom"
        android:imeActionId="666"
        android:inputType="text"/>

and I've checked the effect with the different API levels both in portrait and landscape mode. Here is the outcome.

API level 15 - 4.0.3

In portrait mode the key label is Go and the action id passed to the callback method is 2, accordingly to the imeOptions setting.

In landscape mode the key label/id is Go/2 as the portrait mode, while the button displayed in the input area is Custom/666, accordingly to the imeActionLabel and imeActionId attributes.

API level 16, 17 and 18 - 4.1.2, 4.2.2 and 4.3

Both in portrait and landscape mode the key and the button are displayed with Custom label and are bound to 666 id, ignoring imeOptions attribute.

This mismatch in the behaviour is quite annoying because:

  • with API level >= 16 you can't distinguish between key button and input area button
  • with API level = 15 you can't set any custom text for key button.

Do you know how to obtain this both in API 15 and 16+? Or if there is a way to obtain a consistent behaviour across all (or at least a part of) the API versions?

Maybe I am missing something in the IME settings that can justify the different behaviour...

Thank you very much!

Was it helpful?

Solution

It's actually up to the input method app, not the Android framework itself, to decide what to do with the values you set.

The Android framework just passes the values you set through to the input method, which can then choose what buttons to show on the keyboard or an "extracted" EditText in full-screen view. The Android framework influences the EditorInfo in two ways:-

  • It passes it through EditorInfo.makeCompatible to ensure the values therein are compatible between the keyboard's and the app's targetApiVersions. At the moment this only affects some InputType values, not the editor action, but this could change if new editor actions (or completely new settings) are introduced.

  • It sets the default behaviour for the input method, including the behaviour around full-screen editors. If the input method chooses not to override this default behaviour, then it could end up with behaviour that's different between Android versions. Many keyboards do choose to set their own behaviour, in a way that's consistent between Android versions.

For that reason, it's not so simple to say that a certain EditorInfo field has a certain effect on any given version, and there's no way to ensure a consistent behaviour, even on one Android version. All you're doing is providing hints to the input method, which chooses how to present them to the user.

OTHER TIPS

Just call .setImeActionLabel() programtically in java codes to set actionID (again) to your desired one.

editText.setImeActionLabel(getString(R.string.xxx), EditorInfo.IME_ACTION_GO);

When you start a new Android project, it provides a good hint to your question. There is an Activity called LoginActivity which you can create as a default login screen. This Activity will produce an EditText as so:

            <EditText
                    android:id="@+id/password"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:hint="@string/prompt_password"
                    android:imeActionId="@+id/login"
                    android:imeActionLabel="@string/action_sign_in_short"
                    android:imeOptions="actionUnspecified"
                    android:inputType="textPassword"
                    android:maxLines="1"
                    android:singleLine="true"/>

Now if you read the documentation, you would know that the imeOptions attribute allows you to specify additional actions for a text field. For example, the keyboard that pops up has an action on the bottom right corner like "Next". Using imeOptions you can select another action from a predefined list provided by Android. You can specify something like "actionSend" or "actionSearch".

Once you do that, in order you Activity, you can listen for that action using the setOnEditorActionListener event handler:

    mPasswordView = (EditText) findViewById(R.id.password);
    mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
        @Override
        public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
            if (id == R.id.login || id == EditorInfo.IME_NULL) {
                attemptLogin();
                return true;
            }
            return false;
        }
    });

Notice how we target the imeActionId here. It is another method to target that EditText in your Activity, while also having the flexibility to change the action on the keyboard input.

If someone is designing a custom keyboard for Android and has a problem with the label of the Enter key, you should do the following. In the sample of Android custom keyboard we have the following method in SoftKeyboard.java:

@Override
    public void onStartInput(EditorInfo attribute, boolean restarting)
    {
        super.onStartInput(attribute, restarting);
.
. // the implementation
. 
        mCurKeyboard.setImeOptions(getResources(), attribute.imeOptions);
    }

Change the last line to the following line:

mCurKeyboard.setImeOptions(getResources(), attribute);

Now in LatinKeyboard.java change setImeOptions method like bellow:

void setImeOptions(Resources res, EditorInfo ei)
    {
        if (mEnterKey == null)
        {
            return;
        }

        switch (ei.imeOptions & (EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION))
        {
            case EditorInfo.IME_ACTION_SEND:
                mEnterKey.iconPreview = null;
                mEnterKey.icon = null;
                mEnterKey.label = res.getText(R.string.label_send_key);
                break;
            case EditorInfo.IME_ACTION_GO:
                mEnterKey.iconPreview = null;
                mEnterKey.icon = null;
                mEnterKey.label = res.getText(R.string.label_go_key);
                break;
            case EditorInfo.IME_ACTION_NEXT:
                mEnterKey.iconPreview = null;
                mEnterKey.icon = null;
                mEnterKey.label = res.getText(R.string.label_next_key);
                break;
            case EditorInfo.IME_ACTION_SEARCH:
                mEnterKey.icon = res.getDrawable(R.drawable.sym_keyboard_search);
                mEnterKey.label = null;
                break;
            default:
                mEnterKey.iconPreview = null;
                mEnterKey.label = res.getText(R.string.label_enter_key);
                mEnterKey.icon = null;
                break;
        }

        if (ei.actionLabel != null)
        {
            mEnterKey.iconPreview = null;
            mEnterKey.icon = null;
            mEnterKey.label = ei.actionLabel;
        }
    }

Now your custom keyboard shows proper label based on what is defined in xml file for imeActionLabel.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top