How to call sendKeyDownUpSync in the background? - java

I want to programmatically switch a music track, but this code does not work in the background, how to solve this problem?
Instrumentation inst = new Instrumentation();
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_MEDIA_NEXT);

You need to get an instance of ModuleAndroidKeyboard then call start() on that.
public class ModuleAndroidKeyboard extends Thread {
#Override
public void run() {
Instrumentation inst = new Instrumentation();
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_MEDIA_NEXT);
}
}
ModuleAndroidKeyboard module = new ModuleAndroidKeyboard();
module.start(); // this line executes the codes of run()
To learn more about Thread in Java, visit W3Schools

I figured it out, I had to sign the apk with a system certificate and register INJECT_EVENTS in the manifest, after which everything worked.

Related

Use swing in a different thread

I'm developing a cli-based custom web crawler in Java. Since it needs to have a user-friendly graphical interface for showing the result, I should add a swing frame to that involving some trees, labels, tables and so on.
That graphical interface is one of its switches, and must be started just in case user calls it. Thus, I have to start this interface in a new thread so that the application can proceed with other tasks and update components inside of GUI frame if needs.
My GUI class is some thing like:
public class Frame extends JFrame {
......
public static JLabel urlLabel;
......
public static void run() {
urlLabel = new JLabel();
urlLabel.setText("Test Url");
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Frame().setVisible(true);
}
});
}
.....
}
And, I fork it from my main class like this:
.....
if(cmd.gui){
Frame.run();
Frame.urlLabel.setText("New Url");
}
......
Unfortunately, the text of label doesn't change. I already tested repaint(), revalidate() and such other functions like these, but, nothing turned up.
I tested getText() in order to make sure it is possible to access urlLabel from main class, and it worked (I could retrieved text of label).
I was wondering how I can sort out this issue? (Basically, I need to start a swing frame in a different thread and control its components from the main thread)
Thanks in advance.
If you use invokeLater(), your Runnable will be started in the EventThread after the current operation in this thread is finished. If your label is not updated, it might be that your EventThread is busy doing something else - e.g. crawling the web.
You definitely need to make sure that your crawling work is done in another thread (start a new one, don't use the one that runs anyway, since this is most probably the EventThread). Then you might use invokeLater() in this other Thread to change the label in the EventThread.
Hint: You can check if you are in the EventThread by using SwingUtilities.isEventDispatchThread().
Remember that your data/models will be used by different threads and that this might cause problems when the data is changed in your worker thread while your GUI is trying to display it.
Thank you guys for helping.
Finally, I could overcome this obstacle by using SwingUtilities.invokeLater for updating the label's text.
I mention the approach here, since someone else might need it:
The main class:
public class Frame extends JFrame {
......
private static JLabel urlLabel;
......
public JLabel getU(){
return urlLabel;
}
public static void run() {
urlLabel = new JLabel();
urlLabel.setText("Test Url");
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Frame().setVisible(true);
}
});
}
.....
}
The GUI class:
if(cmd.gui){
Frame().run();
SwingUtilities.invokeLater( new Runnable() {
#Override
public void run() {
gui.getU().setText("New Url");
}
});
}
.....
Just a question about this manner:
Since I need to update some labels and tree nodes a couple of times during crawling, wanted to know if starting a new Runnable for each of those would be overload? If yes, how can I manage that?
---UPDATE---
According to the #xander's comment, it is possible to use lambda instead of Runnable. I think lambda doesn't have overload as much as a new object does.

Android Instrumentation Testing - UI Thread Issues

I am trying to write an Instrumentation Test for my Android app.
I'm running into some weird threading issues and I can't seem to find a solution.
My Original Test:
#RunWith(AndroidJUnit4.class)
public class WorkOrderDetailsTest {
#Rule
public ActivityTestRule<WorkOrderDetails> activityRule = new ActivityTestRule<>(WorkOrderDetails.class);
#Test
public void loadWorkOrder_displaysCorrectly() throws Exception {
final WorkOrderDetails activity = activityRule.getActivity();
WorkOrder workOrder = new WorkOrder();
activity.updateDetails(workOrder);
//Verify customer info is displayed
onView(withId(R.id.customer_name))
.check(matches(withText("John Smith")));
}
}
This resulted in an
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
...
com.kwtree.kwtree.workorder.WorkOrderDetails.updateDetails(WorkOrderDetails.java:155)
The only thing the updateDetails() method does is some setText() calls.
After researching a bit, it seemed like adding a UiThreadTestRule and android.support.test.annotation.UiThreadTest annotation to my test would fix the problem.
#UiThreadTest:
#RunWith(AndroidJUnit4.class)
public class WorkOrderDetailsTest {
//Note: This is new
#Rule
public UiThreadTestRule uiThreadTestRule = new UiThreadTestRule();
#Rule
public ActivityTestRule<WorkOrderDetails> activityRule = new ActivityTestRule<>(WorkOrderDetails.class);
#Test
#UiThreadTest //Note: This is new
public void loadWorkOrder_displaysCorrectly() throws Exception {
final WorkOrderDetails activity = activityRule.getActivity();
WorkOrder workOrder = new WorkOrder();
activity.updateDetails(workOrder);
//Verify customer info is displayed
onView(withId(R.id.customer_name))
.check(matches(withText("John Smith")));
}
}
java.lang.IllegalStateException: Method cannot be called on the main application thread (on: main)
(Note: All of the methods in this stack trace are not my code)
It seems to be giving me mixed results... If it needs to be run on the original thread that created the views but can't run on the main thread, what thread should it be run on?
I'd really appreciate any help or suggestions!
Those instrumentation tests run inside their own app. This also means, they run in their own thread.
You must think of your instrumentation as something you install alongside your actual app, so your possible interactions are 'limited'.
You need to call all view methods from the UIThread / main thread of the application, so calling activity.updateDetails(workOrder); from your instrumentation thread is not the application main thread. This is why the exception is thrown.
You can just run the code you need to test on your main thread like you would do if you were calling it inside your app from a different thread by using
activity.runOnUiThread(new Runnable() {
public void run() {
activity.updateDetails(workOrder);
}
}
With this running your test should work.
The illegal state exception you are receiving seems to be because of your interaction with the rule. The documentation states
Note that instrumentation methods may not be used when this annotation is present.
If you start / get your activity in #Before it should also work.
You can run portion of your test on the main UI thread with the help of UiThreadTestRule.runOnUiThread(Runnable):
#Rule
public UiThreadTestRule uiThreadTestRule = new UiThreadTestRule();
#Test
public void loadWorkOrder_displaysCorrectly() throws Exception {
final WorkOrderDetails activity = activityRule.getActivity();
uiThreadTestRule.runOnUiThread(new Runnable() {
#Override
public void run() {
WorkOrder workOrder = new WorkOrder();
activity.updateDetails(workOrder);
}
});
//Verify customer info is displayed
onView(withId(R.id.customer_name))
.check(matches(withText("John Smith")));
}
In most cases it is simpler to annotate the test method with UiThreadTest, however, it may incur other errors such as java.lang.IllegalStateException: Method cannot be called on the main application thread (on: main).
FYR, here is a quote from UiThreadTest's Javadoc:
Note, due to current JUnit limitation, methods annotated with Before and After will also be executed on the UI Thread. Consider using runOnUiThread(Runnable) if this is an issue.
Please note UiThreadTest (package android.support.test.annotation) mentioned above is different from (UiThreadTest (package android.test)).
The accepted answer is now deprecated
The easiest way to achieve this is simply using UiThreadTest
import android.support.test.annotation.UiThreadTest;
#Test
#UiThreadTest
public void myTest() {
// Set up conditions for test
// Call the tested method
activity.doSomethingWithAView()
// Verify that the results are correct
}
With the androidx test runner a new class was added UiThreadStatement that gives a runOnUiThread method for this.
UiThreadStatement.runOnUiThread {
// call activity here
}
The accepted answer describes what is going on perfectly.
As an addition, in case someone is curious why Espresso's methods that touch the UI e.g. perform(ViewActions ...) don't need to do the same, it is simply because they end up doing it later for us.
If you follow perform(ViewActions ...) you will find it ends up doing the following (in android.support.test.espresso.ViewInteraction):
private void runSynchronouslyOnUiThread(Runnable action) {
...
mainThreadExecutor.execute(uiTask);
...
}
That mainThreadExecutor is itself annotated with #MainThread.
In other words, Espresso also needs to play by the same rules described by David on the accepted answer.

Android Java Textbox.append not working in new thread

I created an application which uses a socket connection to my server. This server sends an information string to the phone which reads this with a BufferedReader.
Now i want to display this information on the screen(in a textbox for example) but the textbox.append command doesn't work in this case.
There is no error but at runtime it won't add the string to the textbox.
Tried the same with textviews. Here the part of this code.
The commands() function is called in the connect progress and the variables are declared at the beginning.
public void commands() throws Exception{
Responce = buffer.readLine();
final TextView textViewToChange = (TextView) findViewById(R.id.textView1);
textViewToChange.setText(Responce);
commands(); }
Would be nice if anyone know how to fix this problem.
Thanks :)
You need to update UI on the main UI Thread. You can use runOnUiThread as below.
runOnUiThread(new Runnable() //run on ui thread
{
public void run()
{
textViewToChange.setText(Responce);
}
});
UI in android is not updateble from another Thread. Look at
AsyncTask
Read this also Ui Update Android

Setting text on jLabel using setText is delayed

I was building a small test tool with Java Swing using Netbeans IDE.
I am trying to update a label, which is somehow not getting 'repainted'/'refreshed'. I looked into a couple of similar questions on SO but was not able to resolve my problem.
private void excelFileChooserActionPerformed(java.awt.event.ActionEvent evt)
{
if(!JFileChooser.CANCEL_SELECTION.equals(evt.getActionCommand()))
{
String selectedFile = excelFileChooser.getSelectedFile().getAbsolutePath();
loaderLabel.setText("Please Wait..");
try {
//This is sort of a blocking call, i.e. DB calls will be made (in the same thread. It takes about 2-3 seconds)
processFile(selectedFile);
loaderLabel.setText("Done..");
missingTransactionsPanel.setVisible(true);
}
catch(Exception e) {
System.out.println(e.getMessage());
loaderLabel.setText("Failed..");
}
}
}
loaderLabel is a JLabel and the layout used is AbsoluteLayout.
So, my problem is "Please Wait..." is never shown. Although call to the method processFile takes about 2-3 seconds, "Please Wait..." is never shown. However, "Done..."/"Failed..." are shown.
If I add a popup (JOptionPane) before the call to processFile, "Please Wait.." is shown. I am not able to clearly understand why this is happening.
Is there a "good practice" that I should follow before a heavy method call? Do I need to call an explicit repaint/refresh/revalidate?
You need to call
processFile(selectedFile);
in another thread (not in the AWT thread). To do so you can do something like this :
Thread t = new Thread(){
public void run(){
processFile(selectedFile);
// now you need to refresh the UI... it must be done in the UI thread
// to do so use "SwingUtilities.invokeLater"
SwingUtilities.invokeLater(new Runnable(){
public void run(){
loaderLabel.setText("Done..");
missingTransactionsPanel.setVisible(true);
}
}
)
}
};
t.start();
Please not that I didn't work with swing for a long time, so there may be some syntax issues with this code.
Have you tried dispatching the call to the EDT with SwingUtilities.invokeLater() ?
http://www.javamex.com/tutorials/threads/invokelater.shtml

Set TextView value inside a thread in android

I am getting a crash under the fllowing circumstances. I am running a thread in the following way:
Thread t = new Thread(){
public void run() {
text.setText("hello");
}
};
t.start;
The crash occurs if I try to set the value of a TextView in my xml, (the reference to text is already available).
Am I doing something fundamentally wrong? Kindly point out where am going wrong.
You can only access user interface components from the UI thread.
Android has a few things to make this easy, such as the method runOnUiThread and the class AsyncTask.
For more reading see Painless Threading and Processes and Threads in the Android documentation.
You should access android ui toolkit widgets only on the UI thread. Read http://developer.android.com/resources/articles/painless-threading.html.
use Handler class and check it for more relevant methods
Handler mHandler;
mHandler=new Handler(){
hdandleMessage(Message what){
text.setText("hello");
}
};
Thread t = new Thread(){
public void run()
{
mHandler.sendEmptyMessage(int what)
}
};
t.start;

Categories