How to select the type of native soft keyboard displayed in native application

505 views
Skip to first unread message

jonlgre...@gmail.com

unread,
May 22, 2018, 10:15:59 AM5/22/18
to android-ndk
I have my own portable C++ ui engine, with my own implementation of text edit fields. I can display a native keyboard, and get and process key events. However, I want to control the type of soft keyboard displayed - so if the edit field is for a phone number, show the appropriate numeric keyboard. In a standard java app you do this by setting the inputType property of an EditText element in a view. I don't have an EditText element, but want to specify the equivalent settings somewhere to control which native keyboard is show. I am happy using JNI and Java interfaces - I just need to know what to set where.

Alex Cohn

unread,
May 24, 2018, 9:04:49 AM5/24/18
to android-ndk
On Tuesday, May 22, 2018 at 5:15:59 PM UTC+3, jonlgre...@gmail.com wrote:
I have my own portable C++ ui engine, with my own implementation of text edit fields. I can display a native keyboard, and get and process key events. However, I want to control the type of soft keyboard displayed - so if the edit field is for a phone number, show the appropriate numeric keyboard. In a standard java app you do this by setting the inputType property of an EditText element in a view. I don't have an EditText element, but want to specify the equivalent settings somewhere to control which native keyboard is show. I am happy using JNI and Java interfaces - I just need to know what to set where.

You can set InputType without EditText, see e.g. https://stackoverflow.com/q/9892617/192373 

BR,
Alex

jonlgre...@gmail.com

unread,
May 24, 2018, 8:42:07 PM5/24/18
to android-ndk
Sorry - I am not sure I understand this. The example you reference is calling the setInputType function through a variable named password, which references an EditText element. At least that's how I understand it. I don't have an EditText element. My problem is finding some object in the input method system which has an interface to set the input type.

KR
Jon

Alex Cohn

unread,
May 26, 2018, 5:01:56 AM5/26/18
to android-ndk
On Friday, May 25, 2018 at 3:42:07 AM UTC+3, jonlgre...@gmail.com wrote:
Sorry - I am not sure I understand this. The example you reference is calling the setInputType function through a variable named password, which references an EditText element. At least that's how I understand it. I don't have an EditText element. My problem is finding some object in the input method system which has an interface to set the input type.

Sorry, wrong link (I had too many tabs open at a time). Try this one or another one.

Jon Green

unread,
May 29, 2018, 12:45:38 PM5/29/18
to android-ndk
Thanks for the links. It looks like the crucial part is overriding the onCreateInputConnection function of the View class. Looking at the java implementation of NativeActivity, it creates a NativeContentView subclass of View. I can't see any way to replace this with my own subclass, so that I can have an implementation of onCreateInputConnection. Is there any way to do that?

KR
Jon

Alex Cohn

unread,
May 30, 2018, 8:23:14 AM5/30/18
to android-ndk
On Tuesday, May 29, 2018 at 7:45:38 PM UTC+3, Jon Green wrote:
Thanks for the links. It looks like the crucial part is overriding the onCreateInputConnection function of the View class. Looking at the java implementation of NativeActivity, it creates a NativeContentView subclass of View. I can't see any way to replace this with my own subclass, so that I can have an implementation of onCreateInputConnection. Is there any way to do that?

The brute-force way would be to clone and rewrite NativeActivity.java. A more elegant approach is to extend android.app.NativeActivity.NativeContentView and in your C++ code replace NativeActivity.mNativeContentView (you cannot, unfortunately, do it in Java class that extends NativeActivity because the field is private). I have never tried the latter myself, and cannot guarantee that there are no hidden complications there.
 
Best of luck,
Alex

Jon Green

unread,
Jun 4, 2018, 10:02:01 AM6/4/18
to android-ndk
I have no idea how to access a private java data member from C++ code.

I don't see how cloning/rewriting NativeActivity would work - the implementation calls a lot of private native functions for which I don't have the source code. I don't know how I would be able to declare and call them from my own version of NativeActivity.

I'm surprised this issue hasn't been solved before. Do other folks not try to mix native software keyboards with their GL native apps? Or if they do, do they not try to control the input type?

It would certainly be easier to implement a soft keyboard in my own ui, but I wanted to let the user use the one they might be familiar with.

KR
Jon

Alex Cohn

unread,
Jun 5, 2018, 3:45:09 AM6/5/18
to android-ndk
On Monday, June 4, 2018 at 5:02:01 PM UTC+3, Jon Green wrote:
I have no idea how to access a private java data member from C++ code.
 
With JNI, you simply don't care whether the field is private or public. GetFieldID() and SetObjectField() work exactly the same.
 
I don't see how cloning/rewriting NativeActivity would work - the implementation calls a lot of private native functions for which I don't have the source code. I don't know how I would be able to declare and call them from my own version of NativeActivity.
 
You don't need to reimplement the native methods of NativeActivity: use the same class name and load the same library. But the source code for JNI layer of NativeActivity is available on https://android.googlesource.com, just as the Java code is.
 
I'm surprised this issue hasn't been solved before. Do other folks not try to mix native software keyboards with their GL native apps? Or if they do, do they not try to control the input type?
They definitely don't. The C++ code is usually cross-platform, and people who work on it prefer not to get their hands dirty with platform-specific tricks. Usually keyboard input is limited in this cross-platform code. The common practice is to handle such UI in Java/Objective-C or maybe Xamarin et al.
 
It would certainly be easier to implement a soft keyboard in my own ui, but I wanted to let the user use the one they might be familiar with.
👍
 
KR
Jon

Sincerely,
Alex

Jon Green

unread,
Jun 5, 2018, 1:10:24 PM6/5/18
to android-ndk
I see about using JNI to access the private field. That makes sense.

 I've been trying to extend the nested NativeActivity.NativeContentView class, but this has package private access, so I couldn't extend it in my own package.

So I then tried redefining my subclass of NativeActivity to be in the android.app package. I moved the files from com/mycompany folders into android/app folders - (but still below my app's src/main/java tree). Any references to package private members of NativeActivity still generate 'can't resolve symbol' errors. I guess whatever file holds all the android class symbols and definitions doesn't export package private symbols, because that file is supposed to hold the complete package, and those symbols shouldn't be accessed outside it?

Is there a trick I'm missing here?

I'm reluctant to go the route of cloning the whole NativeActivity class. It would not be future-proofed if the standard implementation changes in the future, and it seems a lot of effort for such a simple item of functionality.

Alex Cohn

unread,
Jun 5, 2018, 4:00:17 PM6/5/18
to android-ndk
On Tuesday, June 5, 2018 at 8:10:24 PM UTC+3, Jon Green wrote:
I've been trying to extend the nested NativeActivity.NativeContentView class, but this has package private access, so I couldn't extend it in my own package.

So I then tried redefining my subclass of NativeActivity to be in the android.app package. I moved the files from com/mycompany folders into android/app folders - (but still below my app's src/main/java tree). Any references to package private members of NativeActivity still generate 'can't resolve symbol' errors. I guess whatever file holds all the android class symbols and definitions doesn't export package private symbols, because that file is supposed to hold the complete package, and those symbols shouldn't be accessed outside it?

Is there a trick I'm missing here?
 
The specific field we are talking about is not 'package private'. It is 'private' all the way, so moving your files to a matching package cannot help. Actually, there are some ways Java can protect package from being 'extended' by strangers who want to access 'package private' fields and methods, but this is not the case today on Android.

I'm reluctant to go the route of cloning the whole NativeActivity class. It would not be future-proofed if the standard implementation changes in the future, and it seems a lot of effort for such a simple item of functionality.

I empathise with you, but this happens to be the easiest and safest way to achieve your goal.

With compliments,
Alex

Jon Green

unread,
Jun 6, 2018, 3:53:49 PM6/6/18
to android-ndk
I understand the mNativeContentView is private. It is the nested NativeContentView class which is package-private, and which I can't extend in my subclass of NativeActivity (even when I put it in the android.app package), because the compiler says it cannot resolve the NativeActivity.NativeContentView symbol. I also tried calling some of the package-private functions like setWindowFormat (as a compiler test - not for any purpose), and had the same cannot resolve symbol error. Hence my supposition that the package-private symbols are not exported in whatever android jar or dex file the compiler is using.

KR
Jon
Reply all
Reply to author
Forward
0 new messages