I've been trying to figure out how to inject touch/ keyboard events into an Android device for a while now (within and outside of you application).
I found an app that does this without root permissions:
https://play.google.com/store/apps/details?id=com.vmlite.vncserver
Does anyone have any clue how they did it?
If you want to inject touch events on android app without root:
you can use Instrumentation class,
https://developer.android.com/reference/android/app/Instrumentation.html
import android.app.Instrumentation;
public class MainActivity extends Activity {
Instrumentation m_Instrumentation;
public void onCreate(Bundle savedInstanceState) {
m_Instrumentation = new Instrumentation();
int x=0; //your x coord in screen.
int y=0; // your y coord in screen.
m_Instrumentation.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(),MotionEvent.ACTION_DOWN,x, y,0));
m_Instrumentation.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(),MotionEvent.ACTION_UP,x, y,0));
}
}
This method obtains ACTION_DOWN and ACTION_UP event which injects an event on the current layout.
Note: if the injection of your coordinates (x,y) is outside of screen size, the app will crash.
This method injection works only inside app, if you want to inject touch events, you need a rooted device and inject events through adb command.
for non-rooted devices, every time after turning the device completely off and on, you will have to connect your device to a Windows PC or Mac using a USB cable, then run a free desktop program, VMLite Android App Controller, to start the server on your device.
I'm quite sure that at this step it changes the permissions on /dev/input/event.. files and performs the injecting by writing those (sidestepping the Android VM). This technique is detailed in this blog post: Part1, Part2
Related
I'm sending notification to a wearable from a handheld and then displaying background images on cards without text. I'd like to optimize the images for round and square wearables without creating a standalone app and wearable activities.
How would I send a message to the wearable asking what size it is and if it's round or square? I know how to send messages, I'm just looking for the api to look up if it's round or square.
From the following sample, you can see how you would detect this in an activity, but I'd like to detect this in a background service since I don't want to create a standalone wearable app.
https://github.com/mauimauer/AndroidWearable-Samples/blob/8287982332b82cada7bf68a6c5aa88df1bbbcbbe/GridViewPager/Wearable/src/main/java/com/example/android/wearable/gridviewpager/MainActivity.java
My other question shows how to detect if there is a wearable paired, but it only returns node name and node id, no other useful information about the actual wearable.
How to detect if android device is paired with android wear watch
The official way to determine round vs square is to use the WatchInsets class, and the isRound() method. https://developer.android.com/reference/android/view/WindowInsets.html#isRound()
There is a sample named GridViewPager included in the Android SDK Manager for API 20 that shows how to use the isRound() method.
For the rest of your question ... you will need to implement an app that runs on the watch, that would perform this query for you. You can then send a message to the watch, it performs the query, and then send a message back to the phone, for whatever else it is you want to do.
If you look at the DataLayer sample (also in the same place as GridViewPager) it shows how to detect the connection status of the wearable to the phone.
Unofficial way - but for me it was way way easier.
https://github.com/tajchert/ShapeWear
Just copy ShapeWear.java class, and subscribe to screen shape detection event setOnShapeChangeListener() or call method ShapeWear.isRound() (can throw error is shape is not yet determined) or ShapeWear. getShape() - which can result in ShapeWear.SHAPE_UNSURE in same situation.
override this method in ur Engine class that extends CanvasWatchFaceService.Engine
#Override
public void onApplyWindowInsets(WindowInsets insets) {
super.onApplyWindowInsets(insets);
Log.d(TAG, "onApplyWindowInsets");
if (insets.isRound()) {
Log.d(TAG, "Round");
} else {
Log.d(TAG, "Square");
}
}
Context: I'm trying to create a fader-like widget that can have multiple instances in the same view, each of which can be controlled simultaneously by different fingers.
I want to use Qt's gesture recognition system, but I also need some functionality above and beyond the standard Qt::PanGesture. To this end, I've subclassed both QGesture and QGestureRecognizer. In FooGestureRecognizer::recognize(...), I'm currently intercepting both QMouseEvents and QTouchEvents (for the time being, at least).
On Windows I only receive QMouseEvents - I handle them and everything works as expected (though obviously I don't have to deal with the multitouch problem when my input is from a physical mouse). The events I receive (in order):
QEvent::MouseButtonPress
A string of QEvent::MouseMoves
QEvent::MouseButtonRelease
On Android, I receive a strange mix of QMouseEvents and QTouchEvents (in order):
QEvent::TouchBegin
QEvent::MouseButtonPress
QEvent::MouseMove (with no actual change in position)
Another QEvent::MouseButtonPress (not sure why I needed another one)
My actual string of QEvent::MouseMoves, as expected
QEvent::MouseButtonRelease
The global attribute Qt::AA_SynthesizeMouseForUnhandledTouchEvents is true by default. Turning it off changes the events I receive to:
QEvent::TouchBegin
...nothing else.
Here's a precursor question then: What can I do inside QGestureRecognizer::recognize() to tell Qt that I'm handling the QEvent::TouchBegin, and that it doesn't need to synthesize a QEvent::MouseButtonPress for me? event->accept() doesn't appear to make any difference.
The actual question: If (as it appears) Qt is synthesizing MouseEvents from TouchEvents, why do I see I see QEvent::MouseMove and QEvent::MouseButtonRelease but not QEvent::TouchUpdate or QEvent::TouchRelease?
Code is available, but in the interests of conciseness I've not included it here. Please ask if needed.
From the QTouchEvent docs:
The QEvent::TouchUpdate and QEvent::TouchEnd events are sent to the widget or item that accepted the QEvent::TouchBegin event. If the QEvent::TouchBegin event is not accepted and not filtered by an event filter, then no further touch events are sent until the next QEvent::TouchBegin.
The root of this problem is that QGestureRecognizer does not accept the initial TouchBegin, and hence we don't receive any further touch events. I got around this by:
Creating a thin event filter QObject owned by my QGestureRecognizer.
Containing the following code:
bool FooGestureRecognizer::FooEventFilter::eventFilter(QObject *Object, QEvent *Event)
{
if(Event->type() == QEvent::TouchBegin)
{
return true;
}
else
{
return QObject::eventFilter(Object, Event);
}
}
Installing my event filter AND calling setAttribute(Qt::WA_AcceptTouchEvents) on every valid* Target that comes through FooGestureRecognizer::create().
Returning true from eventFilter tells Qt that my fader is interested in receiving further touch events, and these touch events are delivered as expected to the gesture recognizer.
This solution feels like a hack, and one that might not be necessary in future versions of Qt, so I'm going to keep an eye on this code.
Notes:
During the construction of a QGestureRecognizer, create() is called with a null Target (expecting a dummy QGesture to be returned). Watch out for this if you're installing event filters on all Targets.
My application needs to handle desktop mouse events in one way, and multi-finger touch events in another, so I've disabled Qt::AA_SynthesizeMouseForUnhandledTouchEvents. Keeping this enabled may lead to other considerations (e.g. I'm not sure if you'd need to return true for all touch events in eventFilter, so as to avoid them being duplicated as synthesised mouse events).
I am developing an android IME for joysticks. It consists of a Thread that is constantly listening events from a specific device, and then if some conditions are true decides to do something. Is there a way to exclusively bind input events from this device to my IME, so that they won't propagate to applications?
I tried using ioctl(fd,EVIOCGRAB,1) inside a native library to take exclusive control of my device but it doesn't seem to work.
Update: EVIOCGRAB works fine and that's how I solved the problem!
For who's interested I finally found the way to do it:
use this on your "source" device (it is native code that you can use together with libEventInjector):
int fd = open("/dev/input/eventX", O_RDONLY);
if(fd<0) return;
if(ioctl(fd,EVIOCGRAB,1) <0) return;
if everything goes ok the library will have exclusive access to the device, now in your IME start a thread that keeps reading /dev/input/eventX so that you can read the events but they won't propagate to elsewhere.
UPDATE: EVIOCGRAB gives exclusive control only to an instance of a function of your Java class. The best way to intercept events without blocking the device when you close your program is this:
public class Class extends Thread{
boolean running = true;
public void run(){
mySourceDevice.getExclControl();
while(running){
}
mySourceDevice.releaseExclControl();
}
public void interrupt(){
runing=false;
super.interrupt();
}
}
What is the most precise way to measure startup time of an Android app?
By startup time I mean the difference between 2. and 3. :
The app process is not running
User clicks on app icon in the launcher
Main Activity is fully initialized
So I basically need to somehow get time elapsed since JVM started and log it.
I understand I am too late to answer, nonetheless, this precisely answers the question.
This information gets logged on Logcat by default for API version 19 or higher.
From Android 4.4 (API level 19), logcat includes an output line containing a value called Displayed. This value represents the amount of time elapsed between launching the process and finishing drawing the corresponding activity on the screen.
ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms
The key is looking for it in the right place -
If you’re tracking logcat output from the command line, or in a terminal, finding the elapsed time is straightforward. To find elapsed time in Android Studio, you must disable filters in your logcat view. Disabling the filters is necessary because the system server, not the app itself, serves this log.
The extracts are from the documentation.
I'm going to interpret your question as 'Is my app startup time fast enough. How can I check I have done everything I can do?'
The startup time is largely a false metric as it will vary across devices and ROMs. I guess what you're most likely to be interested in is how much of your code is taking a long time to execute and what is potentially blocking the main thread.
I've found the most effective way of doing this is to use Traceview on the app start and then reviewing how long it takes the method to execute and if there are any gaps on the main thread.
Start tracing:
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
Debug.startMethodTracing("startup");
}
}
Stop tracing:
#Override
public void onViewCreated(final View view, final Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Debug.stopMethodTracing();
}
Once the trace has been collected, you should be able to see anything that is having a major impact on startup time. In my case, seen below, there was a big gap on the UI thread where is was being blocked.
It transpired that both Crashlytics and Coremetrics were requiring a call to randomUUID() which was then being synchronized across threads and blocking the main thread. The solution was just to spin up a new thread to initialise the Coremetrics code.
This is something I would not have otherwise picked up with just measuring the startup time, but it actually sped up the app 'startup time' by a few hundred milliseconds.
Here's another snapshot after spinning off a separate thread for Coremetrics initialisation:
Check in adb shell in below manner.
adb shell
adb logcat -b events | grep am_activity_launch_time
[Output]
01-01 12:32:53.469 1236 1262 I am_activity_launch_time:
[0,205360373,com.sec.android.app.clockpackage/.ClockPackage,378,**378**,0]
Remarks:
Launch time for Clock is 378ms.
Wrap the entire onCreate() method in a TimingLogger. Just put this at the beginning:
TimingLogger timings = new TimingLogger(TAG, "methodA");
and this at the end:
timings.dumpToLog();
If you want to drop times at some intermediate step, you can do timings.addSplit("name"); to get the time it took to get to that step.
A simple way to display startup time in android.
Sometimes the Displayed line in the logcat output contains an additional field for total time. For example:
ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms (total +1m22s643ms)
In this case, the first time measurement is only for the activity that was first drawn
Source: Time to initial display
It is possible to implement time tracking using the next code:
Override your Application:
public class CustomApplication extends Application {
public final static long APP_START_TIME = System.currentTimeMillis();
/**
* Do all other application stuff
*/
}
And add few rows to your main Activity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final View contentView = findViewById(android.R.id.content);
contentView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= 16) {
contentView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
contentView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
long launchTime = System.currentTimeMillis() - CustomApplication.APP_START_TIME;
Log.e("TEST", "App launch time = " + launchTime);
}
});
}
}
And don't forget to define your custom application in Manifest:
<application
android:label="#string/app_name"
android:name=".CustomApplication" >
</application>
Important: You have to kill your application before launch, because Application stores static variable which tracks initial time.
Use SysTrace
Also the Trace class can be used to measure sections using
Trace.beginSection("name");
Trace.endSection();
This YouTube video is a quick primer as well.
I think this has been built into Firebase Console, under performance now
One possibility would be is to save the time at the beginning of the onCreate() method and at the end of the onCreate() method and then subtract those times from each other to get the time taken to initialize the app.
I have been trying to get a bitmap screenshot of a SurfaceView for days but the more I look into it, there doesn't seem to be a solution at present for Android OS 2.3.4 based OSs my device from HTC.
So on to Plan B, where I just found out another blog: "On my HTC Evo 3d, all I have to do is hold the power button for 1-2 sec and then hit the home button and it takes a screen shot. No app required." Turns out this works perfectly on my tablet.
I also know from digging around there are these intents: android.intent.action.SCREEN_OFF & android.intent.category.HOME
(So I tried a bunch of code experiments to try to mimic the 2-key combo in code to get a screenshot in this brute force manor. Unfortunately without success).
So my ? -- Does anyone have any insights into a method to invoke this 'screenshot sequence' for my HTC device from java code? (Presume I need to fool the OS into thinking I am holding down the power key AND tap the Home key, simultaneously)...
More: Here is a snip of the code I am attempting:
Button click for test... ...
Thread t = new Thread() {
public void run() {
Instrumentation inst = new Instrumentation();
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_POWER);
Instrumentation inst2 = new Instrumentation();
inst2.sendKeyDownUpSync(KeyEvent.KEYCODE_HOME);
} // run
}; // thread t
Doesnt work as the inst.sendKeyDownUpSync is wrong as I need a sendKeyDown (& hold) behavior or its equivel
Many thanks for any advise. If I do get this working, I will post the solution here. Cheers GH
PS; I presume there is some custom intent under the hood doing this? Is there a system log somewhere to trey to peek at the call tree to find out what it is ?
EDIT (MORE)... 9/24/11
More. Still not working but I am heading down this path & think it is closer...
// Attempt to SIMULATE A Long press (DOWN) + HOME to tell the HTC to invoke the 'Screenshot' command (WARNING: HTC Tablet specific behavior!)
Thread tt = new Thread() {
public void run() {
final KeyEvent dapowerkey = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_POWER);
Handler onesecondhandler = new Handler();
onesecondhandler.postDelayed(new Runnable() {
public void run() {
// fpr about 1 second send power down keystrokes (DOWN ONLY)
while (true) { dispatchKeyEvent(dapowerkey); }
} // we are done running on the timer past time point
}, 750); // 3/4 second key press
// send the HOME keystroke
Instrumentation inst1 = new Instrumentation();
inst1.sendKeyDownUpSync(KeyEvent.KEYCODE_HOME);
} // outer thread run tp mpt block the GUI
}; // outer thread t
tt.start();
...
Also thought if I can send the right intent directly to the proper place on the device that I might be able to kick off a screen capture function directly (which is what I really want. Through some log examinations (when you Long-Power + Home click on HTC) a program called 'com.htc.mysketcher' (FlashActivity) is being called...
Again, if I figure this out then I will post to the group... Cheers GH