Situation: I have a webview with an html input field in it for typing a location, there is a webview sitting underneath it to display suggestions. There is a keyup handler and an onchange handler on that input field. on keyup there is a message sent out to call an api to populate the suggestion webview.
Problem: After typing one character, the input field loses focus. On android 2.3 the keyboard stays up but continued typing does nothing. on android 4.1 the onchange handler gets triggered (as though the user had hit enter to submit what they had typed instead of seleting a suggestion) and the keyboard and webviews get taken away.
Things I have considered: An external loadURL call could cause this (like 'javascript: var...'), calling 'requestFocus' or 'bringToFront' on some other view could also cause this. Setting a event handler on a view tree listener might help clear things up.
Unfortunately, as far as I have been able to tell, no url change is happening, no other views seem to be requesting focus or are being brought to the front. Putting a handler on the view tree listener did not help--it was triggered after the input field lost focus.
I'm out of ideas to try to find the cause of this focus change.
What can I do to investigate this further and solve this problem?
Is loadUrl being called at all (after the first time)? It turns out that loadUrl automatically closes the keyboard. If you are using loadUrl, I found a workaround! Try https://stackoverflow.com/a/18776064/513038.
Related
I've been working on a project which needs to capture keystrokes from an external keyboard (a handheld barcode scanner really) anywhere in the app. Using react-native, this should be trivial, especially with the library react-native-keyevent.
Works perfectly on the initial load. I then navigate to another part of the app (using react-navigation) and try to scan a barcode; nothing happens. I replaced the react-native-keyevent overrides MainActivity.java with some simple Log.d("KeyEvents", "..."), overriding dispatchKeyEvent, onKeyUp, onKeyMultiple and onKeyDown. I only log, then call super.
Same behaviour. Logs fine until I navigate, then it stops. After investigating the Android docs, it seems Views can override key handlers, and thereby 'steal' keystrokes. However I'm stuck finding out which view steals the focus. Also there's really no keyboard handling in react-native by default, so to my understanding, everything should be passed on to the activity.
Wandering hopelessly around in the react-native codebase, I stumbled upon TVEventHandler which I use to log if a view requests focus:
import TVEventHandler from 'react-native/Libraries/Components/AppleTV/TVEventHandler';
(new TVEventHandler).enable('foo', function(){
console.log(arguments);
})
Right before the handlers stop working, this line indeed logs some focus events with a view tag. However, I don't know how to find out which view has a certain tag.
Can someone point me in the right direction where to look?
One of the flags in WindowManager.LayoutParams is FLAG_LOCAL_FOCUS_MODE. It is used together with Window.setLocalFocus method. Unfortunately, the documentation describes the method very succinctly: "Set focus locally". What does it mean? What does it do?
A window with local focus does not report focus changes to the window manager.
While I suspect this is mainly used for automated testing, a real world use case would be an input method for Android TV implemented using Button widgets. You want to be able to focus your buttons in response to dpad navigation, but you don't want these events reported to the window manager because if they are, the window manager will unfocus the window the user is typing in, causing the input method manager to close the input method.
We have a requirment for accessibility that when a given activity opens and the user has TalkBack accessibility on, the client wants the Talk Back to not just read the activity name, but also the text of our welcomeText TextView. That text view is dynamic in that it will say "Welcome, "
I tried doing this in the activity onCreate() by saying:
welcomeText =(TextView)getView().findViewById(R.id.authenticatedNoWishlistWelcomeText);
welcomeText.setFocusableInTouchMode(true);
welcomeText.requestFocus();
but this is not working.. can anyone tell me how i can get Talk Back to read a given TextView upon launch without the user interaction?
The important thing to realize here, is that Focus and Accessibility Focus are not the same thing.
You are looking for the following:
welcomeText.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
Be careful about when you do this. Doing this in onCreate is probably a bad idea, as then it will only happen when the application activity is loaded. What you probably want is for it to happen each time it is resumed. Also, the AT (TalkBack) creates its connection to the Activity at some point in this lifecycle, and so you want to be sure you don't have a race condition. TalkBack must connect to your activity before you post your Accessibility Event.
Though note, that this may be a bad requirement. WCag 3.2.1 and 3.2.3 clearly state that navigation should be consistent and predictable, and part of this is avoiding unexpected shifts of focus. This could be considered a violation of these guidelines, and actually less accessible than not doing so.
I've searched at length and tried the usual suspects, but it's time to ask for help.
My Android activity loads EditText, Spinner and CheckBox values from SQLite happily enough.
The problem is sensing if the user thereafter actually changes a value so I can warn at onBackPressed if unsaved changes were made (i.e. s/he had not hit the 'Save' button).
For example, with an EditText I've tried:
using a TextWatcher.onTextChanged listener, but it gets fired when the EditText is first instantiated, which makes setting a 'data changed' flag meaningless
trapping the various KEY_DOWN events for the DONE, ENTER, NEXT and DEL keys, but with mixed results that wouldn't help with my Spinners and CheckBoxes anyway
onTouchListener (I think, but I'm a little foggy by now), to no avail
I guess what I'm looking for is a View class listener, attached only after the activity has settled down, that fires for subsequent state changes. But, nothing I've searched for fits the bill.
How do others handle this problem?
Thank you for any guidance.
I can't think of any general mechanism that could apply to all kinds of widgets.
Nevertheless, a cleaner solution would be :
to have a model (POJO) that represents all data you display on screen
every change in widgets are reflected in the model
every time a setter is called in the POJO, it compares the new set value with the old one
if a change is made, then it raises an internal flag.
if the flag is raised at onBackPressed, then you show an AlertDialogFragment asking whether changed values should be saved or not.
Is there a way in Android where an android application when active will catch and process all key events (and maybe touch events) before they are delivered to the actual view which is supposed to be handling it?
I know that we can have onKeyDown or similar method in Activity to handle the keyevent, but it is fired only if none of its child views handles it internally.
These view are usually ListView, GridView, ScrollView, etc..
I want to find a way that my keyHandler method is called before that keyEvent is delivered to these views.
Implementation in my keyHandler will be very simple. It will just play a tone upon each event, just like keypress tone, and then forward it to be handled the way it was meant to be by those views or Android framework.
Want to know if its possible beacuse I don't want to write onKeyListener to each and every view in every activity as I have lot of activities and lots of views and it will just become difficult to write the same code everywhere. If there is a way, i can implement that in BaseActivity and derive all my activities by that and go on my way of having default key handler.
I don’t try it myself but I think this one will help you: (just scroll a little bit down to the method mentioned in the text)
Input Event: Event Handlers - Activity.dispatchTouchEvent(MotionEvent)
Looks like this is the chance to catch events before they get to the window. Read the detailed Description here.