Simulating a touch event in Android in a background thread - java

I have used a service which posts code to a handler at an interval of 3 seconds to keep generating a simple touch event (a button press).
This is the service code:
public class BackgroundTouchService extends IntentService
{
public BackgroundTouchService() {
super("BackgroundTouchService");
}
#Override
protected void onHandleIntent(Intent intent)
{
final MotionEvent event = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
MotionEvent.ACTION_BUTTON_PRESS, 400, 400, 0);
final Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run()
{
View v = new View(getApplication());
v.onTouchEvent(event);
handler.postDelayed(this, 3000);
}
});
}
}
In my UI, I have covered the screen with buttons (with appropriate listeners) so that I can easily spot which button has been pressed. However, the main activity loads up and then nothing happens. Why is this?
EDIT:
As Vojtěch Sáze correctly pointed out, the handler in the above code is not associated with the main thread, and hence cannot be used to modify the UI by generating touch events. Hence, I wrote the code for the handler in the main activity itself:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startTouch();
}
private void startTouch()
{
final MotionEvent event = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
MotionEvent.ACTION_BUTTON_PRESS,400.0f, 400.0f, 0);
final Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run()
{
onTouchEvent(event);
handler.postDelayed(this, 3000);
}
});
}
}
However, this still does not do anything. Any ideas?
SOLUTION:
Okay, so in the event type parameter of the MotionEvent.obtain method I had originally specified ACTION_BUTTON_PRESS, however, when I used to separate events to specify ACTION_DOWN and ACTION_UP separately, this seemed to work.
Any explanations as to why this happened are welcome.
In case someone needs this, here is the code:
final MotionEvent event = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
MotionEvent.ACTION_DOWN,400.0f, 400.0f, 0);
final MotionEvent event2 = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
MotionEvent.ACTION_UP, 400.0f, 400.0f, 0);
final Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run()
{
dispatchTouchEvent(event);
dispatchTouchEvent(event2);
handler.postDelayed(this, 3000);
}
});

I think you need to use dispatchTouchEvent method to send the touch event to the view.

I'm not sure if this will help. But definitely there is problem with
final Handler handler = new Handler();
From documentation:
Default constructor associates this handler with the Looper for the current thread. If this thread does not have a looper, this handler won't be able to receive messages so an exception is thrown.
But you don't have main thread in onHandleIntent(). You'll need to create the Handler in the main thread.

Just use code below. Using Android Handler, you need also looper for posting action.
final Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run()
{
onTouchEvent(event);
handler.postDelayed(this, 3000);
}
});

Related

How to remove Handler from adapter

I am using a function into an adapter and I added a Handler to do the refresh every 2s like below:
final Handler refreshHandler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
refreshHandler.postDelayed(this, 2000);
myfunction();
}
};
refreshHandler.postDelayed(runnable, 2000);
When I'm not into the fragment where I deploy the adapter the handler is always reloading.
So my question is, how to stop the handler every time I quit the fragment?
I think you should use the removeCallbacks(Runnable r) method.
That's how you put it in your code:
final Handler refreshHandler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
refreshHandler.postDelayed(this, 2000);
myfunction();
}
};
refreshHandler.postDelayed(runnable, 2000);
#Override
public void onDestroy () {
refreshHandler.removeCallback(runnable);
super.onDestroy ();
}
Something like that wherever you want. Hope you understand

How Can I Stop Runnable Into 2 different Acivity with in Android?

I need to delete a value from SharedPreferences after 5 minutes or when the user finished to do something . So when I add that value I start this:
Activity A
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
mySharedPreferences.removeValue(mContext, Utils.MY_VALUE);
}
}, Utils.TIME_BEFORE_DELETE);
and in the case users finished all I do this:
Activity B
mySharedPrefernces.removeValue(mContext, Utils.MY_VALUE);
But how can I stop the Handle into second activity?? Or is there another way to do it??
you can you boolean variable if you want to cancel this.
create public static boolean to check if the task is cancelled or not.
public static boolean isCanceled = false;
Use this in run() method
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (!isCanceled)
mySharedPreferences.removeValue(mContext, Utils.MY_VALUE);
}
}, Utils.TIME_BEFORE_DELETE);
if you want to cancel then set:
isCanceled = true;
Runnable run = new Runnable() {
#Override
public void run() {
mySharedPreferences.removeValue(mContext, Utils.MY_VALUE);
}
};
Handler handler = new Handler();
handler.postDelayed(run, Utils.TIME_BEFORE_DELETE);
//to dismiss pending runnable
handler.removeCallbacks(run);
A better way to do: Example code
publc static final Handler handler = new Handler();
public static final Runnable runnable = new Runnable() {
public void run() {
try {
Log.d("Runnable","Handler is working");
if(i == 5){ // just remove call backs
handler.removeCallbacks(this);
Log.d("Runnable","ok");
} else { // post again
i++;
handler.postDelayed(this, 5000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
//now somewhere in a method
b1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
handler.removeCallbacks(runnable);
handler.postDelayed(runnable, 5000);
}
});
You can use handler.removeCallbacksAndMessages(null);. More information link
In this case you can use service with sticky flags. So you start service with intent "start_handler" and start handler also. When you need cancel handler you send the intent to stop handler and service. Or when time is passed and handler calls your code you should also stop service.
Using service with sticky flag provides possibility restoring handler. Also you need add some logic saving time when handler was run for correct restoring handler.
For that you can't use direct Runnable inside handler, you need to take one instance of it then you can do this like below,
Runnable myRunnable = new Runnable(){};
Then assign this in handler
handler.postDelayed(myRunnable);
And on no need use below line
handler.removeCallbacks(myRunnable);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
//add your code hare
finish();
}
}, 10000);
by using this way you can stop your runnable in a fix time

Error in derived TimerTask class: `Can't create handler inside thread that has not called Looper.prepare()`

I want to cyclically update an Android Layout. For this purpose I wrote a short class derived from TimerTask.
Unfortunately my code causes an exception and I do not really know, what the problem might be. :(
So maybe anybody could help.
Thanks
Chris
Here's my code:
In the main activity I've got:
private MyLayoutClass m_MyLayout;
...
public void onCreate(Bundle savedInstanceState)
{
...
m_MyLayout = new AdLayout(this);
Timer caretaker = new Timer();
caretaker.schedule(new MyReloadTimerTask(m_MyLayout), 1000, 5000);
...
}
This is my derived TimerTask class:
public class MyReloadTimerTask extends TimerTask
{
private MyLayoutClass m_MyLayout;
public MyReloadTimerTask(MyLayoutClass aLayout)
{
m_MyLayout = aLayout;
}
#Override
public void run()
{
m_MyLayout.doReload();
}
}
The doReload() cannot be executed, I get an exception with this message: Can't create handler inside thread that has not called Looper.prepare()
Timertask runs on a different thread. So you cannot not update/access ui from a background thread.
Probably m_MyLayout.doReload() is updating ui. Use a Handler or runOnUiThread
runOnUiThread(new Runnable() {
#Override
public void run() {
m_MyLayout.doReload()
}
});
Using Handler
Handler m_handler;
Runnable m_handlerTask ;
m_handler = new Handler();
m_handlerTask = new Runnable()
{
#Override
public void run() {
// do something
m_handler.postDelayed(m_handlerTask, 1000);
// repeat some task every 1 second
}
};
m_handlerTask.run();
To cancel the run
m_handler.removeCallbacks(m_handlerTask);

Timeout detection for eventlisteners in Android

I set up event listener, for example: setOnClickListener like this
Button stopBtn = (Button)findViewById(R.id.stop);
stopBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
doMagic();
}
});
I would like to set this listener a timeout event on 10s if button is not pressed. Use case: i have button1 that activates this stopBtn listener for 10s and if timeout comes it becomes deactivated and i need to press button1 to make stopBtn active again.
Im probably doing it wrong:
final Handler myHandler = new Handler();
startBtn = (Button)findViewById(R.id.start);
myHandler.postDelayed(new Runnable() {
public void run() {
startBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i(TAG,"runned");
}
});
}
}, 10000);
After 10s im still able to click it and that is probably cos event listener is still attached. How can i detach it even if i don't know if its fired or not.
A delayed Runnable posted on a Handler could manage that:
myHandler.postDelayed(new Runnable() {
public void run() {
if(something happened) {
// magic work
} else {
// turn off the event
}
}
, 10000);
You can init the Handler as an instance variable by using this code:
final Handler myHandler = new Handler();
Delayed actions can be arranged by using a Handler. Specifically check the 2 methods: postAtTime(Runnable, long) and postDelayed(Runnable, long).
It is easy to create a Handler, just use its default constructor Handler handler = new Handler() within the Activity.onCreate(Bundle state). Then wrap your desired action into a Runnable and pass to the handler.

Error in countdowntimer in android?

I am working on a layout which shows a tab like structure on bottom of the layout. Which I need to show on double tap and then hide it after 5 sec. So I am using this countdown timer:
public void timer()
{
cdt=new CountDownTimer(5000,1000) {
#Override
public void onTick(long millisUntilFinished) {
System.out.println("Timer Working"+millisUntilFinished+"");
}
#Override
public void onFinish() {
System.out.println("Finished");
main =(LinearLayout)findViewById(R.id.parent);
ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)main.getLayoutParams();
mlp.height=420;
set_up_views();
find_module();
tl.setVisibility(View.INVISIBLE);
}
}.start();
}
But I dont know how to stop and restart this timer. How can I do?
I suggest you not to Use CountDownTimer for this case.
Use Handler.postDelayed(Runnable runnable, long delay)
public class yourActivity extends Activity
{
public Handler handler = new Handler();
...
public void hideAfter5Sec()
{
handler.postDelayed(new Runnable()
{
View view = findViewById(view_to_hide);
view.setVisibility(View.INVISIBLE);
}, 5000);
}
}
postDelayed will execute that code after 5Sec.
EDITED:
postDelayed will be call only once after 5 Sec through Lopper.loop(). If there are multiple call to hideAfter5Sec() then only you will get multiple call to postDelayed.
If you have multiple call hideAfter5Sec() i dont think there is any wrong because hideAfter5Sec() is just hidding it. so if it one or many your view will be hidden.
If in case you want to hide only in the last call of hideAfter5Sec() use this variant.
public class yourActivity extends Activity
{
public Handler handler = new Handler();
public long lastHideAfter5Sec = 0L;
...
public void hideAfter5Sec()
{
lastHideAfter5Sec = System.currentTimeMillis();
handler.postDelayed(new Runnable()
{
if(System.currentTimeMillis() - lastHideAfter5Sec < 5000)
return;
View view = findViewById(view_to_hide);
view.setVisibility(View.INVISIBLE);
}, 5000);
}

Categories

Resources