Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to show the soft keyboard on native activity

When I try to use ANativeActivity_showSoftInput(), it doesn't bring up the soft keyboard.

I have tried using ANativeActivity_showSoftInput(engine->app->activity, ANATIVEACTIVITY_SHOW_SOFT_INPUT_FORCED) and ANativeActivity_showSoftInput(engine->app->activity, ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT) to show softinput, but also failed.

I read the source code, and I found after start nativeActivity, NativeContentView(extend View) will be created, and when call ANativeActivity_showSoftInput, it will call showSoftInput() in java side. I think maybe the softkeyboard is not turned on.

Can you help me?

like image 686
Miles Avatar asked May 03 '11 03:05

Miles


People also ask

How do I open a soft keyboard?

By default, the soft keyboard may not appear on the emulator. If you want to test with the soft keyboard, be sure to open up the Android Virtual Device Manager ( Tools => Android => AVD Manager ) and uncheck "Enable Keyboard Input" for your emulator. Now restart the emulator.


3 Answers

I have got exactly the same problem. No way to show the Keyboard using this API.

The only way I found was to use JNI but of course I am not satisfied with that solution:

android_app* mApplication;

...

void displayKeyboard(bool pShow) {
    // Attaches the current thread to the JVM.
    jint lResult;
    jint lFlags = 0;

    JavaVM* lJavaVM = mApplication->activity->vm;
    JNIEnv* lJNIEnv = mApplication->activity->env;

    JavaVMAttachArgs lJavaVMAttachArgs;
    lJavaVMAttachArgs.version = JNI_VERSION_1_6;
    lJavaVMAttachArgs.name = "NativeThread";
    lJavaVMAttachArgs.group = NULL;

    lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs);
    if (lResult == JNI_ERR) {
        return;
    }

    // Retrieves NativeActivity.
    jobject lNativeActivity = mApplication->activity->clazz;
    jclass ClassNativeActivity = lJNIEnv->GetObjectClass(lNativeActivity);

    // Retrieves Context.INPUT_METHOD_SERVICE.
    jclass ClassContext = lJNIEnv->FindClass("android/content/Context");
    jfieldID FieldINPUT_METHOD_SERVICE =
        lJNIEnv->GetStaticFieldID(ClassContext,
            "INPUT_METHOD_SERVICE", "Ljava/lang/String;");
    jobject INPUT_METHOD_SERVICE =
        lJNIEnv->GetStaticObjectField(ClassContext,
            FieldINPUT_METHOD_SERVICE);
    jniCheck(INPUT_METHOD_SERVICE);

    // Runs getSystemService(Context.INPUT_METHOD_SERVICE).
    jclass ClassInputMethodManager = lJNIEnv->FindClass(
        "android/view/inputmethod/InputMethodManager");
    jmethodID MethodGetSystemService = lJNIEnv->GetMethodID(
        ClassNativeActivity, "getSystemService",
        "(Ljava/lang/String;)Ljava/lang/Object;");
    jobject lInputMethodManager = lJNIEnv->CallObjectMethod(
        lNativeActivity, MethodGetSystemService,
        INPUT_METHOD_SERVICE);

    // Runs getWindow().getDecorView().
    jmethodID MethodGetWindow = lJNIEnv->GetMethodID(
        ClassNativeActivity, "getWindow",
        "()Landroid/view/Window;");
    jobject lWindow = lJNIEnv->CallObjectMethod(lNativeActivity,
        MethodGetWindow);
    jclass ClassWindow = lJNIEnv->FindClass(
        "android/view/Window");
    jmethodID MethodGetDecorView = lJNIEnv->GetMethodID(
        ClassWindow, "getDecorView", "()Landroid/view/View;");
    jobject lDecorView = lJNIEnv->CallObjectMethod(lWindow,
        MethodGetDecorView);

    if (pShow) {
        // Runs lInputMethodManager.showSoftInput(...).
        jmethodID MethodShowSoftInput = lJNIEnv->GetMethodID(
            ClassInputMethodManager, "showSoftInput",
            "(Landroid/view/View;I)Z");
        jboolean lResult = lJNIEnv->CallBooleanMethod(
            lInputMethodManager, MethodShowSoftInput,
            lDecorView, lFlags);
    } else {
        // Runs lWindow.getViewToken()
        jclass ClassView = lJNIEnv->FindClass(
            "android/view/View");
        jmethodID MethodGetWindowToken = lJNIEnv->GetMethodID(
            ClassView, "getWindowToken", "()Landroid/os/IBinder;");
        jobject lBinder = lJNIEnv->CallObjectMethod(lDecorView,
            MethodGetWindowToken);

        // lInputMethodManager.hideSoftInput(...).
        jmethodID MethodHideSoftInput = lJNIEnv->GetMethodID(
            ClassInputMethodManager, "hideSoftInputFromWindow",
            "(Landroid/os/IBinder;I)Z");
        jboolean lRes = lJNIEnv->CallBooleanMethod(
            lInputMethodManager, MethodHideSoftInput,
            lBinder, lFlags);
    }

    // Finished with the JVM.
    lJavaVM->DetachCurrentThread();
}
like image 88
Ratamovic Avatar answered Oct 17 '22 21:10

Ratamovic


Another way is to go with a hybrid solution where you extend the NativeActivity in java and have helper functions for showing and hiding keyboard.

import android.view.inputmethod.InputMethodManager;
import android.content.Context;

public class MyNativeActivity extends android.app.NativeActivity
{
    public void showKeyboard()
    {
        InputMethodManager imm = ( InputMethodManager )getSystemService( Context.INPUT_METHOD_SERVICE );
        imm.showSoftInput( this.getWindow().getDecorView(), InputMethodManager.SHOW_FORCED );
    }

    public void hideKeyboard()
    {
        InputMethodManager imm = ( InputMethodManager )getSystemService( Context.INPUT_METHOD_SERVICE );
        imm.hideSoftInputFromWindow( this.getWindow().getDecorView().getWindowToken(), 0 );
    }
}

And on the native side...

void DisplayKeyboard( bool bShow )
{
    // Attaches the current thread to the JVM.
    JavaVM* pJavaVM = m_pNativeActivity->vm;
    JNIEnv* pJNIEnv = m_pNativeActivity->env;

    JavaVMAttachArgs javaVMAttachArgs;
    javaVMAttachArgs.version = JNI_VERSION_1_6;
    javaVMAttachArgs.name = "NativeThread";
    javaVMAttachArgs.group = NULL;

    jint nResult = pJavaVM->AttachCurrentThread( &pJNIEnv, &javaVMAttachArgs );
    if ( nResult != JNI_ERR ) 
    {
        // Retrieves NativeActivity.
        jobject nativeActivity = m_pNativeActivity->clazz;
        jclass ClassNativeActivity = pJNIEnv->GetObjectClass( nativeActivity );

        if ( bShow )
        {
            jmethodID MethodShowKeyboard = pJNIEnv->GetMethodID( ClassNativeActivity, "showKeyboard", "()V" );
            pJNIEnv->CallVoidMethod( nativeActivity, MethodShowKeyboard );
        }
        else
        {
            jmethodID MethodHideKeyboard = pJNIEnv->GetMethodID( ClassNativeActivity, "hideKeyboard", "()V" );
            pJNIEnv->CallVoidMethod( nativeActivity, MethodHideKeyboard );
        }

        // Finished with the JVM.
        pJavaVM->DetachCurrentThread();
    }
}

This allows you to deal with the Android specific stuff in java as it was intended and have the native code call into wrappers, thus reducing the complexity in syntax on the native side.

like image 40
Shammi Avatar answered Oct 17 '22 21:10

Shammi


I had a lot of trouble trying to close the soft keyboard when the view changed, until I realized I had to remove it specifically from the view that called it:

InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);

There's also a showSoftInput method that should probably work (assuming it does what the method name says it does) in a similar way, where it needs a view to anchor itself to:

InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.showSoftInput(editText.getWindowToken(), 0);

Can't really test this myself at the moment, but I figured it might be able to help you and would be worth a shot. Just make sure the "editText" is linked to the EditText you want to receive the input.

like image 30
Cruceo Avatar answered Oct 17 '22 22:10

Cruceo