I want to detect "user inactivity" in my Android app. To be more precise: I want to detect if the user has NOT done any interaction with my app (touching the screen, scrolling, input texts ...) for a specific time. Technically I use a timer that is reseted on each (user) interaction.
In my activity, I override the onUserInteraction method to detect interactions like scrolling, touching the screen ...
#Override
public void onUserInteraction(){
resetInactiveTimer();
}
Unfortunately, onUserInteraction is not called when the user interacts with the soft keyboard. I think the reason is, that the soft keyboard is not part of my Activity.
For the edit texts in my app I use TextWatcher and the onTextChanged method which works fine. But my app also contain a WebView that loads arbitrary web pages. Of course some web pages could contain input fields and I do not know how to detect that the user interacts with the soft keyboard to edit those text fields.
Still interested in this?
Your activity implements KeyEvent.Callback, so you can override onKeyDown:
#Override
public boolean onKeyDown (int keyCode, KeyEvent event) {
resetInactiveTimer();
return false;
}
Alternatively, (in the most common circumstance) if the key is pressed with the cursor in an EditText or similar, you will need implement an OnKeyListener and use the onKey method to call resetInactiveTimer();
Related
I want to be able to know when a user is done entering text in an EditText control. I'm thinking maybe it's best to know when the keyboard is closed or something similar. This is using Kotlin on Android app. I'm not sure why it's so hard to find basic answers like this. Maybe I'm searching with the wrong question (new to Android dev).
Using keyboard close as an indicator that the user finished entering text is a bad idea (the user might open the keyboard again to enter more text). A better solution would be to explicitly require for the user to indicate that he has finished entering the data.
You could use a "submit" button.
You can also set the android:imeOptions of EditText to actionDone and set a listener on the EditText.
editText.setOnEditorActionListener(new EditText.OnEditorActionListener() {
#Override
public boolean onEditorAction(EditText v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
//do your stuff
return true;
}
return false;
}
});
Update - Assuming keyboard close as the indicator is bad for a couple of reasons,
There is no 'proper' way to monitor the soft keyboard. You could try listening to the focus of the EditText or you could use the height difference to guesstimate whether the soft keyboard is open or closed(the option used in most keyboard listener libraries). But these aren't reliable and might break in production.
It's an 'unexpected' application behavior for the user. For example, the keyboard can be removed by pressing the back button. In general, the user would expect that the action would not proceed if the back button is pressed. But if you listen to keyboard close, then it would end up resulting in poorer UX.
There are no actual reasons why you would want to use keyboard close as the trigger. If you want to perform the action as the user types, then you should use TextWatcher, otherwise stick to explicit confirm options.
use onFocusChangeListener to know if the user has finished to add text and has leave the textInput focus.
Example
editText?.onFocusChangeListener =
View.OnFocusChangeListener { _,
hasFocus ->
if (!hasFocus) {
// code to execute when EditText loses focus
}
}
I have an application which needs to log the user out after no activity is detected. I am using a timer that resets when the user interacts with the app. I have been using OnUserInteraction method; however this does not track interaction with the Soft Keyboard.
#Override
public void onUserInteraction() {
super.onUserInteraction();
logoutTimer.RestartTimer();
}
My problem is that this application allows the user to input text (without limit) and the application times the user out in the middle of inputting text. Is there another way of listening for Keys being pressed on a softkeyboard? (I know I can create a listener on the editText but there are multiple editTexts on different fragments and was wondering if there is a better way)
I guess there is no way to do this via onUserInteraction only. You can extend EditText, set a TextWatcher in it and catch all interactions with this EditText in TextWatcher's callbacks. Then you have to substitute this newly created EditText of yours in all places where you use to have standard EditText. I tried to override onKeyEvent() method inside the activity which hosts my EditText and refresh the timer in onKeyDown or onKeyUp, but to no avail. SoftInput seems to redirect all touches not to your activity, but to its own Window, that is why you won't see any keyEvents in activity.
I extended InputMethodService hoping to use this Service for showing a soft keyboard even though a hard keyboard is connected(based off the following post Show soft keyboard even though a hardware keyboard is connected). Is there a way to bind to this service within the app without having to declare it in the manifest? The end result is to have InputMethodService.onEvaluateInputViewShown return true so that the soft keyboard will show even though a hard keyboard is connected.
I would like to use the extended class MultiInputMethodService with the inputmethodmanager in show/hideSoftKeyboard:
public class MultiInputMethodService extends InputMethodService {
#Override
public boolean onEvaluateInputViewShown () {
Log.i("onEvaluateInputViewShow","onEvaluateInputViewShown");
return true;
}
}
my activity:
private void showSoftKeyboard() {
InputMethodManager imm = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,InputMethodManager.HIDE_IMPLICIT_ONLY );
}
private void hideSoftKeyboard() {
InputMethodManager imm = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(this.myInput.getEditText().getWindowToken(), 0);
}
The IMS framework really needs to be used as a whole. If you want to be the keyboard, the user will need to select you as the default keyboard via settings. If you were to try to bind with the service directly I'm not sure what the result would be, but my guess would be that it ends badly. By having the user set you as the default keyboard, you will automatically be used as the keyboard in all apps.
Of course, you can't just set that yourself, for security purposes. Otherwise keyboards would be fighting over the setting. The user has to set it manually.
EDIT:
I found the documentation you are referring to(under the "Security Section"):
http://developer.android.com/reference/android/view/inputmethod/InputMethodManager.html
A client application can ask that the system let the user pick a new
IME, but can not programmatically switch to one itself. This avoids
malicious applications from switching the user to their own IME, which
remains running when the user navigates away to another application.
An IME, on the other hand, is allowed to programmatically switch the
system to another IME, since it already has full control of user
input.
The user must explicitly enable a new IME in settings before they can
switch to it, to confirm with the system that they know about it and
want to make it available for use.
I am trying to define a set of buttons that allow the user to enter data into an EditText box. I want all the default functionality of an EditText box except for the pop up of the soft keyboard. the only data to be allowed to enter into the EditText box should be the data from the buttons I have defined. I am trying to suppress the soft keyboard by catching the touch event and returning true. (per the conversation found on this thread)
private OnTouchListener txtTouchListener = new OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
//Return true to suppress the passing of the event on to the OS
return true;
}
};
The problem is that this method then blocks the long click event from firing. To solve this I can return false and then handle the long click event. However, this then makes the short click bring up the soft keyboard. Also, upon long click not only is the soft keyboard suppressed, but so is the context menu. I am looking for a way to stop the keyboard from appearing on a short (or long) click but keep all other functionality (updating the cursor position on short click, on long click show the EditText context menu, etc.)
Any ideas on this is greatly appreciated!
This thread suggests:
EditText.setInputType(InputType.TYPE_NULL);
Or you set the inputType in the XML Attribute to none.
Not tried it myself though.
I am trying to execute an event mouse press within my android application. When the user enters a CARRIAGE RETURN when entering text into a text field. I would like to execute a mouse button press on an ADD button when that character is detected in my OnClickListener for that EditText ui.
Peter -
It sounds like what you want to do is override the EditorAction for the given EditText, and then programmatically perform the same action as the OnClickListener. For example:
EditText inputText; //This is either created in code or inflated via XML
Button addButton; //This is either created in code or inflated via XML
inputText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
addButton.performClick();
//Tell the system you consumed the action event
return true;
}
});
The actionId can be a useful property too, as it reports the specific action (DONE, NEXT, etc.) based on the soft keyboard method shown...but keep in mind that if the user presses enter from a hardware keyboard the action will ALWAYS be EditorInfo.IME_NULL, so it may not serve your purpose to monitor this value.
This is a safer method than overriding KeyEvent listeners, as you run less risk of consuming events you don't want and didn't know you stole.
Hope that helps!