findClass() returning java.lang.Class - Xposed General

When i am trying to call a method (to start the music in grooveshark) i come across an error that i believe is because XposedHelpers.findClass() is returning an unwanted class.
Here is the code that is giving the issue
Code:
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
XposedHelpers.callMethod(XposedHelpers.findClass("com.grooveshark.android.lib.player.AsyncPlayer", lpparam.classLoader),"play", true);
}
And here is the error that it is returning
Code:
08-20 01:30:31.038 2390-2390/? I/Xposed﹕ java.lang.NoSuchMethodError: java.lang.Class#play(java.lang.Boolean)#bestmatch
at de.robv.android.xposed.XposedHelpers.findMethodBestMatch(XposedHelpers.java:271)
at de.robv.android.xposed.XposedHelpers.findMethodBestMatch(XposedHelpers.java:284)
at de.robv.android.xposed.XposedHelpers.callMethod(XposedHelpers.java:947)
...
This error is here because callMethod should be calling
Code:
com.grooveshark.android.lib.player.AsyncPlayer#play
but instead it calls
Code:
java.lang.Class#play
because "Class" is being passed to it from findClass, not the correct class
What needs to be done to get the right class/call the right method?
Edit:
i have tried using param.thisObject, but the method i want (play) is in a different package than the onStart method (that i am hooking). The method i am hooking (onStart) is in
Code:
com.grooveshark.android.v1.activity.Home
and using param.thisObject just gives me
Code:
java.lang.NoSuchMethodError: com.grooveshark.android.v1.activity.Home#play(java.lang.Boolean)#bestmatch
as it is in the wrong package

I'm assuming play is a static method, since you wouldn't be able to call it without an instance otherwise.
If that's the case, you should use XposedHelpers.callStaticMethod.

GermainZ said:
I'm assuming play is a static method, since you wouldn't be able to call it without an instance otherwise.
If that's the case, you should use XposedHelpers.callStaticMethod.
Click to expand...
Click to collapse
When i changed it to
Code:
XposedHelpers.callStaticMethod(XposedHelpers.findClass("com.grooveshark.android.lib.player.AsyncPlayer", lpparam.classLoader),"play", true);
I get the error
Code:
I/Xposed﹕ java.lang.NullPointerException: expected receiver of type com.grooveshark.android.lib.player.AsyncPlayer, but got null
That being said...if i hook into a method in the same class as play, i will use the 'pause' method as an example, and call
Code:
XposedHelpers.callMethod(param.thisObject,"play", true);
then play is correctly called (which has the unfortunate effect of preventing me from stopping the music)
So i still think the issue is that i do not know how to correctly use findClass/callMethod
Here is "play"
Code:
public void play(boolean paramBoolean) {
while (true) {
try {
if (this.context == null) {
this.logger.severe("No context set! Has the player been released?");
return;
}
if (this.playableSong == null) {
this.logger.severe("playableSong not set!");
continue;
}
} finally {}
this.logger.info("playing " + getPlayableSong() + " current state: " + this.state.name() + ", successive? " + paramBoolean);
this.isSuccessive = paramBoolean;
this.isPaused = false;
if (this.state != State.PAUSED) {
State localState1 = this.state;
State localState2 = State.PREPARED;
if (localState1 != localState2);
} else {
try {
this.mp.start();
setState(State.PLAYING);
startPolling();
} catch (IllegalStateException localIllegalStateException) {
this.mp.reset();
setState(State.IDLE);
}
continue;
}
if (this.state == State.PREPARING) {
this.handler.sendEmptyMessage(2);
} else {
setState(State.PREPARING);
Message localMessage = this.handler.obtainMessage(0, this.context);
this.handler.sendMessage(localMessage);
}
}
}

dillonr said:
When i changed it to
Code:
XposedHelpers.callStaticMethod(XposedHelpers.findClass("com.grooveshark.android.lib.player.AsyncPlayer", lpparam.classLoader),"play", true);
I get the error
Code:
I/Xposed﹕ java.lang.NullPointerException: expected receiver of type com.grooveshark.android.lib.player.AsyncPlayer, but got null
That being said...if i hook into a method in the same class as play, i will use the 'pause' method as an example, and call
Code:
XposedHelpers.callMethod(param.thisObject,"play", true);
then play is correctly called (which has the unfortunate effect of preventing me from stopping the music)
So i still think the issue is that i do not know how to correctly use findClass/callMethod
Here is "play"
Code:
public void play(boolean paramBoolean) {
while (true) {
try {
if (this.context == null) {
this.logger.severe("No context set! Has the player been released?");
return;
}
if (this.playableSong == null) {
this.logger.severe("playableSong not set!");
continue;
}
} finally {}
this.logger.info("playing " + getPlayableSong() + " current state: " + this.state.name() + ", successive? " + paramBoolean);
this.isSuccessive = paramBoolean;
this.isPaused = false;
if (this.state != State.PAUSED) {
State localState1 = this.state;
State localState2 = State.PREPARED;
if (localState1 != localState2);
} else {
try {
this.mp.start();
setState(State.PLAYING);
startPolling();
} catch (IllegalStateException localIllegalStateException) {
this.mp.reset();
setState(State.IDLE);
}
continue;
}
if (this.state == State.PREPARING) {
this.handler.sendEmptyMessage(2);
} else {
setState(State.PREPARING);
Message localMessage = this.handler.obtainMessage(0, this.context);
this.handler.sendMessage(localMessage);
}
}
}
Click to expand...
Click to collapse
If play is a static method: use callStaticMethod.
If play is not a static method: you can't use findClass to call it, you'll need the class' instance.

GermainZ said:
If play is a static method: use callStaticMethod.
If play is not a static method: you can't use findClass to call it, you'll need the class' instance.
Click to expand...
Click to collapse
play isn't static...How would i get the class' instance?

dillonr said:
play isn't static...How would i get the class' instance?
Click to expand...
Click to collapse
Using getObjectField, assuming there is one. If not, you can try creating an instance (using the newInstance method, IIRC).
I'd think if this is the right way to do it, though. Although I don't know what you're trying to do, it sounds like you should be hooking a different method.

GermainZ said:
Using getObjectField, assuming there is one. If not, you can try creating an instance (using the newInstance method, IIRC).
I'd think if this is the right way to do it, though. Although I don't know what you're trying to do, it sounds like you should be hooking a different method.
Click to expand...
Click to collapse
Hopefully this clears it up...What i am trying to do is have grooveshark automatically play music when my phone connects to the bluetooth speakers in my car
Currently i am working out how to make the music play, but i already have the code there to check that bluetooth is connected (although untested, as i wrote it last night and haven't been out to the car to check it).
When i am finished, tasker will open grooveshark when my phone connects to the bluetooth speakers and my xposed module will check that bluetooth is connected and then start playing the music. Hooking onto the onStart method seemed to be the easiest way to get everything going when grooveshark opens
Would it be possible to see an example of getObjectField/newInstance? I promise i have tried to figure it out myself, i'm just not sure what to do, and looking at the source of XposedHelpers.java gives me an idea of what is available, but not of how to use what is available

dillonr said:
Hopefully this clears it up...What i am trying to do is have grooveshark automatically play music when my phone connects to the bluetooth speakers in my car
Currently i am working out how to make the music play, but i already have the code there to check that bluetooth is connected (although untested, as i wrote it last night and haven't been out to the car to check it).
When i am finished, tasker will open grooveshark when my phone connects to the bluetooth speakers and my xposed module will check that bluetooth is connected and then start playing the music. Hooking onto the onStart method seemed to be the easiest way to get everything going when grooveshark opens
Would it be possible to see an example of getObjectField/newInstance? I promise i have tried to figure it out myself, i'm just not sure what to do, and looking at the source of XposedHelpers.java gives me an idea of what is available, but not of how to use what is available
Click to expand...
Click to collapse
OK, here's a general post that should show you how to use various methods, along with some common pitfalls.
I'm not going to write complete code, so use this as an example but don't copy/paste.
If you're using an app to view this post, I'd recommend you open it in a web browser so you get pretty syntax highlighting and formatting.
Let's assume we have two classes, Class1 and Class2. Class1:
Java:
class Class1 {
Object someVariable;
final static int SOME_FINAL_STATIC_INT = 30;
Context context;
Class2 class2Instance;
method void Class1(Context context) {
this.context = context;
class2Instance = Class2.getInstance(context);
}
method void someMethod(String stringArg, int intArg) {
for (int i = intArg; i < SOME_FINAL_STATIC_INT ; i++) {
class2Instance.doSomething(stringArg);
}
}
}
Class2:
Java:
class Class2 {
Context context;
Class2 instance;
method void Class2(Context context) {
this.context = context;
instance = this;
}
static method Class2 getInstance(Context context) {
if (instance == null)
instance = new Class2(context);
return instance;
}
method void doSomething(String stringArg) {
// do something
}
}
We want to change someMethod's behavior so it always goes from 0 to 10 instead of intArg to SOME_FINAL_STATIC_INT .
We know that we can modify the arguments of a method directly (using param.args[index]) and a static int field using setStaticInt, so it should be easy to do… right? Nope.
Why not? Because SOME_FINAL_STATIC_INT , being static and final, will be replaced by the compiler. In other words, this:
Java:
for (int i = intArg; i < SOME_FINAL_STATIC_INT ; i++) {
class2Instance.doSomething(stringArg);
}
Will actually become this when compiled:
Java:
for (int i = intArg; i < 30; i++) {
class2Instance.doSomething(stringArg);
}
So, how do you replace the 30 now? You don't. Depending on the situation, you'll have to use alternative ways to accomplish what you want. The most general one is to replace the method:
Java:
findAndHookMethod("my.package.Class1", lpparam.classLoader, "someMethod", String.class, int.class, new XC_MethodReplacement() {
[PLAIN]@Override[/PLAIN]
Object replaceHookedMethod(param) {
// we want to go from 0 to 10 only
for (int i = 0; i < 10; i++) {
// get class2Instance
Object class2Instance = getObjectField(param.thisObject, "class2Instance");
// call doSomething
callMethod(class2Instance, doSomething, param.args[0]);
}
}
});
And we're done. We wanted to modify the for loop, and we did. We then wanted to call a method, but since that method belongs to another class, we needed that class' instance first.
Assume we don't have an instance of the class, what do we do then? Well, you could create an instance yourself… but keep in mind this may not lead to the result you want if the application expects (and uses) only one instance.
For example, let's assume there was no class2Instance in Class1. We could create one like this:
Java:
findAndHookMethod("my.package.Class1", lpparam.classLoader, "someMethod", String.class, int.class, new XC_MethodReplacement() {
[PLAIN]@Override[/PLAIN]
Object replaceHookedMethod(param) {
// we want to go from 0 to 10 only
for (int i = 0; i < 10; i++) {
// find Class2
Class Class2 = findClass("my.package.Class2", lpparam.classLoader);
// we need to get a context to create an instance of Class2, since its constructor needs a context
Context context = (Context) getObjectField(param.thisObject, "context");
// create class2Instance
Object class2Instance = newInstance(Class2, context);
// we can also call Class2.getInstance, which would be a better choice, although such a method is not always available.
// Object class2Instance = callStaticMethod(Class2, "getInstance", context);
// call doSomething
callMethod(class2Instance, doSomething, param.args[0]);
}
}
});
To recap: we got the context using getObjectField, just as before.
We then got the Class for Class2 and used it to create a new instance. (We also could've called the static method, which would have given us the existing instance, if any; such a method isn't always available, though).
The rest was similar to the previous example.
I hope this explains how to use some of the methods Xposed offers clearly. Good luck.

I am still unable to call a method (i think that it is because the method i am calling is in a different package (.lib.player.AsyncPlayer) than the one i am hooking (.v1.activity.Home), so i can't get a context/instance.)
I think it is time that i drop this module, and spend my time elsewhere, maybe coming back to it later when i learn more

dillonr said:
I am still unable to call a method (i think that it is because the method i am calling is in a different package (.lib.player.AsyncPlayer) than the one i am hooking (.v1.activity.Home), so i can't get a context/instance.)
I think it is time that i drop this module, and spend my time elsewhere, maybe coming back to it later when i learn more
Click to expand...
Click to collapse
Your issue has been addressed in the legacy thread. See this and [URL="http://forum.xda-developers.com/showpost.php?p=40166637&postcount=980]this[/URL]

NipplesOfTheFuture said:
Your issue has been addressed in the legacy thread. See this and [URL="http://forum.xda-developers.com/showpost.php?p=40166637&postcount=980]this[/URL]
Click to expand...
Click to collapse
If all he needs is a context, he can simply use AndroidAppHelper.currentApplication().

Related

Having Trouble Changing a Color

I'm trying to change the color of text from black to white. Modding the app with smali, I have narrowed it down to this portion of code. Where this.b(-16777216); would be the color black.
Code:
@Override
public void t() {
super.t();
this.p.setVisibility(8);
this.q.setVisibility(8);
this.n.setVisibility(8);
this.o.setVisibility(8);
this.u.setVisibility(8);
this.t.setVisibility(8);
this.r.setVisibility(8);
this.w.setVisibility(8);
this.x.setVisibility(8);
this.z.setVisibility(8);
this.C.setVisibility(8);
this.B.setVisibility(8);
this.D.setVisibility(8);
this.i.setVisibility(8);
this.k.setVisibility(8);
this.b(-16777216);
this.B.setOnClickListener(null);
this.D.setOnClickListener(null);
this.I = false;
}
So far this is where I am at. Logs not throwing any errors.
Edit.. I've also placed param.thisObject in place of null with no luck as well.
Code:
public class ClassName implements IXposedHookLoadPackage {
public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
if (!lpparam.packageName.equals("com.app.package"))
return;
findAndHookMethod("com.app.package.blah.blah.Class", lpparam.classLoader, "t", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
XposedHelpers.setIntField(null, "b", Color.WHITE);
}
});
}
}
Try using Xposedhelpers.callMethod(param.thisObject, "b", Color.WHITE) instead of setIntField.
set***Field methods are for the purpose of setting values of field members of object.
"b" is not a field member. It's a method (function).
C3C076 said:
Try using Xposedhelpers.callMethod(param.thisObject, "b", Color.WHITE) instead of setIntField.
set***Field methods are for the purpose of setting values of field members of object.
"b" is not a field member. It's a method (function).
Click to expand...
Click to collapse
OMG THANK YOU! It worked perfectly. I've been trying everything since Monday. Since I know what works and re-reading the section on the wiki about the callMethod helper, it makes a lot more sense now. Thanks again .
C3C076 said:
Try using Xposedhelpers.callMethod(param.thisObject, "b", Color.WHITE) instead of setIntField.
set***Field methods are for the purpose of setting values of field members of object.
"b" is not a field member. It's a method (function).
Click to expand...
Click to collapse
One last thing.. before I spend days trying to figure it out again lol. I'm getting a cannot cast to android....TextView with the following:
Edit: I think it is because I forgot to add the following:
Code:
String text = tv.getText().toString();
tv.setText(text);
I'll test when I get home.
Code:
XposedHelpers.findAndHookMethod("com.app.package.blah.blah.Class", lpparam.classLoader, "a", "com.app.package.blah.blah.AnotherClass", TextView.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
TextView tv = (TextView) param.thisObject;
tv.setTextColor(Color.WHITE);
}
});
This is what the portion of code looks like for the text color I am trying to change: textView.setTextColor(-16777216);
Code:
@Trace
private void a(FeedItem feedItem, TextView textView) {
this.b(chatFeedItem, textView);
if (feedItem instanceof StatefulChatFeedItem && (feedItem.Y() || feedItem.Z())) {
textView.setTextColor(this.b.getResources().getColor(2131230734));
return;
}
textView.setTextColor(-16777216);
}
Nevermind.. didn't work
93Akkord said:
Nevermind.. didn't work
Click to expand...
Click to collapse
Arguments of a function you are hooking are accessed using param.args array, not param.thisObject.
param.thisObject refers to the instance of an object you are working with. In your case,
it's an instance of "com.app.package.blah.blah.Class" class.
So proper way of getting that TextView which is a second argument of a function you are hooking is:
TextView tv = (TextView) param.args[1];
C3C076 said:
Arguments of a function you are hooking are accessed using param.args array, not param.thisObject.
param.thisObject refers to the instance of an object you are working with. In your case,
it's an instance of "com.app.package.blah.blah.Class" class.
So proper way of getting that TextView which is a second argument of a function you are hooking is:
TextView tv = (TextView) param.args[1];
Click to expand...
Click to collapse
Oh wow.. thanks. That worked. I actually tried TextView tv = (TextView) param.args[0];, among numerous other combinations, and never thought to try [1]. It makes me feel happy and sad at the same time lol. I appreciate the help :highfive:
dupe
param.args array is zero based and TextView is a second argument of a function. so:
- param.args[0] is FeedItem argument
- param.args[1] is TextView argument

[Q] startActivity

Trying to disable incoming call activity launch. Its class is com.android.phone.InCallScreen.
Launched like this:
Code:
PhoneGlobals phoneglobals;
phoneglobals.startActivity(PhoneGlobals.createInCallIntent());
Code:
public class PhoneGlobals extends ContextThemeWrapper {
...
public static Intent createInCallIntent() {
Intent intent = new Intent("android.intent.action.MAIN", null);
intent.setFlags(0x10840000);
intent.setClassName("com.android.phone", getCallScreenClassName());
return intent;
}
static String getCallScreenClassName() {
return (com.android.phone.InCallScreen.class).getName();
}
}
PhoneGlobals doesn't have startActivity() method, but it extends ContextThemeWrapper which extends ContextWrapper which has a startActivity(Intent) method.
Hooked it successfully, but my hook is not being executed. Tried to hook all startActivity(*) methods in android.content.ContextWrapper and android.app.ContextImpl, same result.
Hm, looks like incoming call activity is also called through the notification using
Code:
builder.setFullScreenIntent(pendingintent, true);

A few things about Android Studio

1) Can anyone bring me back code of the press (BACK) devices such as the Galaxy LG etc., that kind of goes back button all the time back
2) Is it possible to make any changes in SPINNER another color? That is when I open the SPINNER any changes / Line will be a different color I choose?
3) just an example I built an app that chooses an image from the media Phone, after it came to ImageView this over and across, it's some of the images
How do I IMAGEVIEW rotation? I realized it is called rotation How do I use it?
1)
Code:
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
// do something
yourView.notifyBackPressed();
return false;
}
return super.onKeyDown(keyCode, event);
}
And in your View have to implement method, for example notifyBackPressed();
2) Good question i need to know that!
3)
Code:
private void rotate(float degree) {
final RotateAnimation rotateAnim = new RotateAnimation(0.0f, degree,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
rotateAnim.setDuration(0);
rotateAnim.setFillAfter(true);
imgview.startAnimation(rotateAnim);
}
Bye
cristaccio85 said:
1)
Code:
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
// do something
yourView.notifyBackPressed();
return false;
}
return super.onKeyDown(keyCode, event);
}
And in your View have to implement method, for example notifyBackPressed();
2) Good question i need to know that!
3)
Code:
private void rotate(float degree) {
final RotateAnimation rotateAnim = new RotateAnimation(0.0f, degree,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
rotateAnim.setDuration(0);
rotateAnim.setFillAfter(true);
imgview.startAnimation(rotateAnim);
}
Bye
Click to expand...
Click to collapse
The best, thanks 7

Hooking a method from background service

Hi,
I'm trying to hook some of the Android APIs in my module. I have a simple app consists of two activities (MyActivity, DisplayMessageActivity) and one service (LocationService). "MyActivity" starts "LocationService" using the following code:
Intent intent = new Intent(getApplicationContext(), LocationService.class);
startService(intent);
"MyActivity" can also start "DisplayMessageActivity" by pressing a button using the following code:
Intent intent = new Intent(this, DisplayMessageActivity.class);
startActivity(intent);
In the "LocationService", I register a GPS location listener at the start of service, which will update the "DisplayMessageActivity" upon change in the location or provider status as follows:
public int onStartCommand(Intent intent, int flags, int startId) {
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
Intent intent1 = new Intent(getApplicationContext(), DisplayMessageActivity.class);
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent1);
}
public void onStatusChanged(Location location) {
Intent intent1 = new Intent(getApplicationContext(), DisplayMessageActivity.class);
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent1);
}
public void onProviderEnabled(Location location) {
Intent intent1 = new Intent(getApplicationContext(), DisplayMessageActivity.class);
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent1);
}
public void onProviderDisabled(Location location) {
Intent intent1 = new Intent(getApplicationContext(), DisplayMessageActivity.class);
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent1);
};
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 0, locationListener);
return Service.START_NOT_STICKY;
}
I hooked the method "startActivity" in my module as follows:
XposedHelpers.findAndHookMethod("android.app.Activity", lpparam.classLoader, "startActivity", android.content.Intent.class, new XC_MethodHook() {
@override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Intent intent = (Intent) param.args[0];
String destination = intent.getComponent().getClassName().split(lpparam.packageName+".")[1];
XposedBridge.log("(Intent,"+destination+")");
}
});
The module successfully logs the invocation of "startActivity" when I press the button (starting "DisplayMessageActivity" from "MyActivity"). But when "startActivity" is invoked from the service, the module does not log the invocation. I'm new to Xposed and I'm not sure why this is happening. Is this because the "startActivity" is called from a background service? What can I do to resolve the issue?
I really appreciate your help
You can go to rovo89's Github for help, he is keen at helping other's development.
You are hooking on startActivity method of android.app.Activity class.
This method is specific for Activity class only as it overrides startActivity from super class (ContextWrapper and Context which is abstract). Calling startActivity within Service class is like calling completely different method that's why your hook won't work here.
To be able to cover both cases, you will have to hook on lower level in class hierarchy.
Probably the best would be to hook onto startActivity(Intent intent, Bundle bundle) of ContextWrapper class as it is sure all calls made from either Activity or Service will go this path.
So
Code:
XposedHelpers.findAndHookMethod("android.content.ContextWrapper", lpparam.classLoader, "startActivity", Intent.class, Bundle.class, new XC_MethodHook() {
....
}

Module stops working as soon as I load a native library (Please help)

Hi,
First, a disclaimer.
I am a Java and xposed noob. My background is in embedded C development so I can get by with some simple Java code and thanks to the great tutorials online I have been able to put together an xposed module but I'm struggling with a problem that is beyond my abilities now and am reaching out to the community for help.
Next, the background.
I have an Android head unit in my car. There is an app that provides me with CarPlay functionality but none of the controls on the steering wheel work with the app. When I analysed the code I found that they handle all of their button inputs using proprietary methods that do not inject an event into any input streams. I wrote an xposed module to hook the button press methods and then inject a proper input into one of the event streams.
Initially I tried to use the command line 'input' command to do this but since it is a Java app and takes about 1s to load it was too slow. My only other option was to create a virtual device on an input stream that I could then use to inject keypresses through the hooked method. To create a virtual device I needed to write C code that my xposed module would be able to access through the JNI. Long story short, after some pain I was able to get the native library integrated into the project and compiling using the NDK.
Finally, the problem.
When I was using the module without the native library it worked but just with a large delay because of the time it takes to load the 'input' java app. I was able to see logs from the module in the logcat as I hooked the method and as I went through the various actions within the hook.
As soon as I introduce the native library though the entire xposed module just stops running completely. I do not get any logs from the module even though I have installed, activated and rebooted. It shows up in the xposed installer but it just does nothing. The funny thing is that this happens even if I make no reference whatsoever to any native functions within the library. All I need to do to kill the module is to build it with the System.loadlibrary line in the Main.java uncommented. As soon as I comment that piece of code out the module starts to hook the function and output logs again. Below is the code from the Main.Java that I am referring to. I am happy to make any manifest, C and gradle files available too. Looking for any ideas as to why the module dies completely as soon as I include this...
Code:
package projects.labs.spike.zlink_xposed_swc;
import de.robv.android.xposed.XposedBridge;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.IXposedHookZygoteInit;
import de.robv.android.xposed.XSharedPreferences;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import de.robv.android.xposed.XposedHelpers;
import android.app.AndroidAppHelper;
import android.content.Intent;
import android.os.Bundle;
import android.content.Context;
/* shellExec and rootExec methods */
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ByteArrayOutputStream;
import android.view.KeyEvent;
import android.media.AudioManager;
public class Main implements IXposedHookLoadPackage {
public static final String TAG = "ZLINK_XPOSED ";
public static void log(String message) {
XposedBridge.log("[" + TAG + "] " + message);
}
//public native int CreateVirtualDevice();
//public native int SendPrev();
@Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
log("handleLoadPackage: Loaded app: " + lpparam.packageName);
if (lpparam.packageName.equals("com.syu.ms")) {
findAndHookMethod("module.main.HandlerMain", lpparam.classLoader, "mcuKeyRollLeft", new XC_MethodHook() {
@Override
protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {
// previous
log("PREVKEYHIT");
//rootExec("input keyevent 88");
log("EVENTSENT");
//Below was trying to use media keys which zlink never responded to...
/* Context context = (Context) AndroidAppHelper.currentApplication();
AudioManager mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PREVIOUS);
mAudioManager.dispatchMediaKeyEvent(event);
KeyEvent event2 = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PREVIOUS);
mAudioManager.dispatchMediaKeyEvent(event2);*/
//Below is the failed broadcast intent method...
/*Context mcontext = (Context) AndroidAppHelper.currentApplication();
Intent i = new Intent("com.android.music.musicservicecommand");
i.putExtra("command", "pause");
mcontext.sendBroadcast(i);*/
}
});
}
}
public static String rootExec(String... strings) {
String res = "";
DataOutputStream outputStream = null;
InputStream response = null;
try {
Process su = Runtime.getRuntime().exec("su");
outputStream = new DataOutputStream(su.getOutputStream());
response = su.getInputStream();
for (String s : strings) {
s = s.trim();
outputStream.writeBytes(s + "\n");
outputStream.flush();
}
outputStream.writeBytes("exit\n");
outputStream.flush();
try {
su.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
res = readFully(response);
} catch (IOException e) {
e.printStackTrace();
} finally {
Closer.closeSilently(outputStream, response);
}
return res;
}
public static String readFully(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length = 0;
while ((length = is.read(buffer)) != -1) {
baos.write(buffer, 0, length);
}
return baos.toString("UTF-8");
}
[COLOR="Red"] static {
System.loadLibrary("native-lib");
}[/COLOR]
}
The issue with native library is quite strange and I cannot help with it as my experience with native libs is zero.
But maybe try a different method of injecting media key events.
Create a method:
Code:
void injectKey(int keyCode) {
try {
final long eventTime = SystemClock.uptimeMillis();
final InputManager inputManager = (InputManager)
mContext.getSystemService(Context.INPUT_SERVICE);
int flags = KeyEvent.FLAG_FROM_SYSTEM;
XposedHelpers.callMethod(inputManager, "injectInputEvent",
new KeyEvent(eventTime - 50, eventTime - 50, KeyEvent.ACTION_DOWN,
keyCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, flags,
InputDevice.SOURCE_KEYBOARD), 0);
XposedHelpers.callMethod(inputManager, "injectInputEvent",
new KeyEvent(eventTime - 50, eventTime - 25, KeyEvent.ACTION_UP,
keyCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, flags,
InputDevice.SOURCE_KEYBOARD), 0);
} catch (Throwable t) {
// something went wrong
XposedBridge.log(t.getMessage());
}
}
Then just do: injectKey(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
And maybe try playing with different KeyEvent flags and attrs.
Thanks so much for this suggestion! Any idea if this injects at a java level or if it depends on there being a keyboard input device available on one of the /dev/input/eventX streams? The android device that I am using has no keyboard available on any of those input streams. Will give it a try nonetheless
C3C076 said:
The issue with native library is quite strange and I cannot help with it as my experience with native libs is zero.
But maybe try a different method of injecting media key events.
Create a method:
Code:
void injectKey(int keyCode) {
try {
final long eventTime = SystemClock.uptimeMillis();
final InputManager inputManager = (InputManager)
mContext.getSystemService(Context.INPUT_SERVICE);
int flags = KeyEvent.FLAG_FROM_SYSTEM;
XposedHelpers.callMethod(inputManager, "injectInputEvent",
new KeyEvent(eventTime - 50, eventTime - 50, KeyEvent.ACTION_DOWN,
keyCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, flags,
InputDevice.SOURCE_KEYBOARD), 0);
XposedHelpers.callMethod(inputManager, "injectInputEvent",
new KeyEvent(eventTime - 50, eventTime - 25, KeyEvent.ACTION_UP,
keyCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, flags,
InputDevice.SOURCE_KEYBOARD), 0);
} catch (Throwable t) {
// something went wrong
XposedBridge.log(t.getMessage());
}
}
Then just do: injectKey(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
And maybe try playing with different KeyEvent flags and attrs.
Click to expand...
Click to collapse
looxonline said:
Thanks so much for this suggestion! Any idea if this injects at a java level or if it depends on there being a keyboard input device available on one of the /dev/input/eventX streams? The android device that I am using has no keyboard available on any of those input streams. Will give it a try nonetheless
Click to expand...
Click to collapse
Simply use whatever InputDevice that you think should work in your case.
The method basically calls this:
https://android.googlesource.com/pl.../android/hardware/input/InputManager.java#869
which is then propagated to Input Manager Service here:
https://android.googlesource.com/pl...oid/server/input/InputManagerService.java#598
which then calls nativeInjectInputEvent

Categories

Resources