I need to limit number of key events handled per second.
The idea is, because in my app users can use keyboard.
When user hold down on right navigation button, for example.
I don't want to handle every event, because my app can get stucked in calculation loop.
And then force close, wait dialog appears.
I want to handle 2,3 events per second and other just to ignore.
So I can add little cool down time for the app and calculation thread.
Is is possible?
I think I must use some timers or simple sleep function in my key listener, but I can't figure out right way to do this.
Any idea?
A simple solution would be doing some time comparison when you receive a key event:
// a variable in your class:
private long mPreviousKeyEventTime = 0;
// in the key event handling function:
if(System.currentTimeMillis() - mPreviousKeyEventTime < 300) return;
mPreviousKeyEventTime = System.currentTimeMillis();
300 is the time in milliseconds - change it to suite your needs.
Edit: if the keyboard is also used for typing, then make these restrictions only when navigating.
Related
I am making a custom IME. I am trying to track when the user manually changes the selection region of text (as opposed to the selection changing as a result of actions from the IME itself, like commitText).
To do this, I am keeping track of where the IME expects the selection position to be, and compares it to the actual selection position from onUpdateSelection.
For example, to commit text I use:
private fun commitTextToInputConnection(text: String)
{
moveExpectedSelection(text.length)
service.currentInputConnection.commitText(text, 1)
}
However, if I do:
commitTextToInputConnection("Test1")
commitTextToInputConnection("Test2")
I find that, in order, the following sequence occurs:
1 - ExpectedSelectionPosition updates for "Test1"
2 - ExpectedSelectionPosition updates for "Test2"
3 - onUpdateSelection for "Test1" is called
4 - onUpdateSelection for "Test2" is called
Obviously, this order is incorrect, and leads to my IME having an incorrect ExpectedSelectionPosition.
The strangest thing is that, for some Activities, the sequence of ExpectedSelectionPosition updates and onUpdateSelection calls always occur in the correct order. For other Activities, they consistently occur in the same (wrong) order.
What is going on here? I'm guessing commitText, etc, must be asynchronous, leading to this race condition, but this is not mentioned at all in the documentation.
Are there are any work-arounds to this issue? Or, are there any other ways I can listen exclusively for changes in text selection triggered manually by the user, and not the IME?
The solution was to use InputConnection.beginBatchEdit and InputConnection.endBatchEdit.
Any changes made to the currentInputConnection within a 'batchEdit' block are lumped together into a single onUpdateSelection call, at the end.
For example, when the following is executed:
service.currentInputConnection.beginBatchEdit()
commitTextToInputConnection("Test1")
commitTextToInputConnection("Test2")
service.currentInputConnection.endBatchEdit()
onUpdateSelection is called only once, after all the changes in the block have been made.
I am trying to implement a series of notifications based on radio button options the user selects. The notifications date and time will set depending on both radio button options and the user selected date.
for example the user selects Option 1, 2 and 3 along with Jan 1st 2017 and 12 notifications are set every couple of days/weeks depending on said options.
Before I get too far into this, am I just looking at a complex if then statement to set these notifications or am i missing another solution?
When your if-else statements get too long you might be needing a switch statement instead. You said there are twelve notification options so a switch could do this just fine.
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html
Remember to separate each option in a modular fashion using different classes, or methods so that you just have to call each block of code.
A lot of switcing or if/else can also be a symptom of you trying to express intrinsically polymorphic code. You are essentially replicating the vtable the compiler would do for you. Following separating business logic from view (rendering) logic -- ie some form of MVC -- you could associate a subclass with each radio button to which the button delegates the logic when it is pressed (btw you might not necessarily need separate subclasses). The controller of each radio button may have a reference to some other object which stores the final frequency of days/hours/minutes, etc for each to call the alarm. So as each radio button is pressed, it delegates to its controller which in turn interprets the value of the radio button and in turn calls into the alarm controller, incrementing / decrementing some value using some appropriate API.
I know it might sound like over-engineering but it is quite simple to set up and it is likely that you will minimally need that alarm controller for other details (which also makes it a lot easier to test; you definitely do not want to shove business logic in your views (activities) as it makes testing a nightmare). So if you wish to simplify this, you could forego each button's individual controller and instead have each button directly invoke the alarm controller API if you prefer to update it.
I need to get the current value of the proximity sensor (rather than implementing a continuous listener). On some devices, the first reported value will be a default value (e.g. "FAR") that isn't necessarily accurate, and actual values will only start appearing after the second or third reading. At the moment, I've implemented a 1-second Handler and use the last reported value (after the second has elapsed) as the "true" value, but this solution seems crude (and slow). Is there a better approach that works on all 4.0+ devices? I could simply count up until I've received 3 readings, but on some devices (e.g. GNex), the first value will be correct, and the value will only change after that if there is actually a change in the sensor.
You can do what I did:
You probably have an if statement on the listener - one logic flow for near and one for far.
Instead of waiting on the handler - do this:
if(near) {
myHandler.removeCallbacks(yourRunnableForFar);
myHandler.postDelayed(yourRunnableForNear,100);
else {
myHandler.removeCallbacks(yourRunnableForNear);
myHandler.postDelayed(yourRunnableForFar,100);
}
Notice that the inaccurate first reading(s) will immediately be followed by an accurate one, so the last one "wins".
This code works well if you didn't register sensors other than proximity. If you have a flow of readings from other sensors, than use a static flag (such as the boolean near) to trigger the handler calls only on state change.
Elaboration:
yourRunnableForFar and yourRunnableForNear - are placeholders that implement Runnable to hold your app logic on what to do when the proximity sensor returns "near" (event.values[0] == 0) or "far" (not 0).
myHandler is just any Handler you might created, or declare one just for this with Handler myHandler = new Handler(Looper.getMainLooper());
You might want to acquire a proximity lock on near, and release it and clear the listener on far. But this is app logic that might be completely different from app to app.
I was looking through ViewConfiguration class documentation and I found getJumpTapTimeout() method. Description says it is used to determine whether user wants to perform a "jump" tap or a regular one. The user has to complete jump tap within this time or it will be a regular one. The question is what is this jump tap anyway?
I've looked through the source, but it doesn't give any clues. Jump tap timeout is 500 ms, so is the long press timeout. So if I keep my finger for more than 500 ms on the same spot without moving, this is a long press, and it's not a tap. Tap timeout is 115 ms, so I have to at least not move my finger for this time or this won't be a tap. But then I have to do something until my 500 ms expire. Only what exactly?
It is same as tap applied to active page elements, but used in earlier versions of webview, now this parameter is simply redefined inside webview as tap_timeout, now it sess to be used only for dpads
// This should be ViewConfiguration.getTapTimeout()
// But system time out is 100ms, which is too short for the browser.
// In the browser, if it switches out of tap too soon, jump tap won't work.
// In addition, a double tap on a trackpad will always have a duration of
// 300ms, so this value must be at least that (otherwise we will timeout the
// first tap and convert it to a long press).
I have seen its usage in one of Google's open source project Eyes-Free Android Applications more specifically inside ProcessorFocusAndSingleTap.java Inside performClick(AccessibilityNodeInfoCompat node)
For clarity I am mentioning here what It was used for
If a user quickly touch explores a content i.e, (event stream < ViewConfiguration.getTapTimeout()), then to avoid sending an unintentional ACTION_CLICK they have Switched off clicking on content.
Basically , It's The timeout after which an event is no longer considered a tap
you jump from one app to the other. Jump will tell your phone that you jumped and will no longer keep the previous app on.
I have an app out that involves keeping track of information over time. Part of the app is a reset button. In order to avoid accidental resets, I made that button respond only to long-clicks. However, that approach confused about 20% of my new users, who thought that the reset button must not be working.
Is there a more intuitive (and standard) way to protect a button from accidental presses? (If not, I can add some sort of custom message to the button I have . . . )
A Thilo said, a confirmation dialog is the standard answer.
This is good reading if you haven't already:
http://www.codinghorror.com/blog/2010/03/the-opposite-of-fitts-law.html
Basically, make it small! Long click is a good answer, but unless there's a "press and hold" label right underneath that, users are going to have trouble - that violates the user model, since users aren't used to having to do that (I probably wouldn't be able to figure it out).
On the iPhone it's fairly standard to have "slide" buttons (like the unlock) for operations like this, since it's much more difficult to accidentally slide. You could implement something similar to that, but it might be overkill for this problem.
Another vote for Thilo and a confirmation dialog.
Also Google/Android is trying to get devs to use the long press as a Quick Action UI pattern. See Android Developers Blog entry on Twitter app
All though this is kinda a workaround, it still works.
case R.id.bReset:
long startTime = System.nanoTime();
boolean running = true;
//show dialog with a single button - cancel. Outside the loop. Upon cancel, set cancelled to true.
//You can use DialogFragment or AlertDialog
while(running && !canceled){
long elapsed = (System.nanoTime() - startTime) / 1000000;
if(elapsed > securityTime && !canceled) {//set security time to amount of seconds * 1000
//Dismiss dialog
//reset
}
}
break;
From the currently accepted answer:
As Thilo said, a confirmation dialog is the standard answer.
It does not have to be a confirmation dialog, but if accidental press the user should have the opportunity to cancel the action while at the same time no further action is required if the user wanted to do it.