Related
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().
I have a textview that shows your amount of money and i would like the ui to update every second to visually show how much money you have in real time. Would i be able to accomplish this with a timer?, and if so what would it look like.
Hello,
You should do inside your class, outside of any method:
Code:
TextView tv;
String calculatedString;
MyAsyncTask mAsync = null;
Timer timer = null;
TimerTask task = null;
private class MyAsyncTask extends AsyncTask<String, Void, String> {
public MyAsyncTask(){
}
@Override
protected String doInBackground(String... params) {
//Background operation in a separate thread
//Write here your code to run in the background thread
//calculate here whatever you like
calculatedString = ....;
return null;
}
@Override
protected void onPostExecute(String result) {
//Called on Main UI Thread. Executed after the Background operation, allows you to have access to the UI
tv.setText(calculatedString);
}
@Override
protected void onPreExecute() {
//Called on Main UI Thread. Executed before the Background operation, allows you to have access to the UI
}
}
inside the onCreate after super and setContentView:
Code:
tv = (TextView) findViewById(R.id.tv); //your tv id here
final Handler handler = new Handler();
timer = new Timer();
task = new TimerTask() {
@Override
public void run() {
handler.post(new Runnable() {
public void run() {
MyAsyncTask mAsync = new MyAsyncTask();
mAsync.execute();
}
});
}
};
timer.schedule(task, 0, 1000); //Every 1 second
If you still need help, feel free to ask
I have attached 2 screenshots showing the errors i was given after inputting. Any idea how to fix this?
mmdeveloper10 said:
Hello,
You should do inside your class, outside of any method:
Code:
TextView tv;
String calculatedString;
MyAsyncTask mAsync = null;
Timer timer = null;
TimerTask task = null;
private class MyAsyncTask extends AsyncTask<String, Void, String> {
public MyAsyncTask(){
}
@Override
protected String doInBackground(String... params) {
//Background operation in a separate thread
//Write here your code to run in the background thread
//calculate here whatever you like
calculatedString = ....;
return null;
}
@Override
protected void onPostExecute(String result) {
//Called on Main UI Thread. Executed after the Background operation, allows you to have access to the UI
tv.setText(calculatedString);
}
@Override
protected void onPreExecute() {
//Called on Main UI Thread. Executed before the Background operation, allows you to have access to the UI
}
}
inside the onCreate after super and setContentView:
Code:
tv = (TextView) findViewById(R.id.tv); //your tv id here
final Handler handler = new Handler();
timer = new Timer();
task = new TimerTask() {
@Override
public void run() {
handler.post(new Runnable() {
public void run() {
MyAsyncTask mAsync = new MyAsyncTask();
mAsync.execute();
}
});
}
};
timer.schedule(task, 0, 1000); //Every 1 second
If you still need help, feel free to ask
Click to expand...
Click to collapse
Hello,
For the first image:
You have to import the AsyncTask.
add this
Code:
import android.os.AsyncTask;
with the other imports in your java file.
For your second image:
You haven't wrote the line
Code:
setContentView(R.layout.activity_main);
under your super.onCreate(savedInstanceState); and then the code I said above (I said that on my post )
inside onCreate, where activity_main is your xml layout. And you should have inside that layout, a TextView with an id "tv" (or whatever you like)
and then:
Code:
tv = (TextView) findViewById(R.id.tv); //your tv id here
R.id.tv must much the id you have in your layout. Replace it with the actual id of your TextView. If your id is "tv", write R.id.tv, if it is "mytv" write R.id.mytv. ( I said that on my post also)
Can you show your layout file? (XML - your activity_main.xml). You said that you have a TextView Where is your TextView?
Ok I fixed the problems stated and now only have these two errors remaining
mmdeveloper10 said:
Hello,
For the first image:
You have to import the AsyncTask.
add this
Code:
import android.os.AsyncTask;
with the other imports in your java file.
For your second image:
You haven't wrote the line
Code:
setContentView(R.layout.activity_main);
under your super.onCreate(savedInstanceState); and then the code I said above (I said that on my post )
inside onCreate, where activity_main is your xml layout. And you should have inside that layout, a TextView with an id "tv" (or whatever you like)
and then:
Code:
tv = (TextView) findViewById(R.id.tv); //your tv id here
R.id.tv must much the id you have in your layout. Replace it with the actual id of your TextView. If your id is "tv", write R.id.tv, if it is "mytv" write R.id.mytv. ( I said that on my post also)
Can you show your layout file? (XML - your activity_main.xml). You said that you have a TextView Where is your TextView?
Click to expand...
Click to collapse
Have you imported this?
Code:
import java.util.logging.Handler;
If so, change it to
Code:
import android.os.Handler;
Im not at the computer but I think that should solve my issue I will keep you updated
Sent from my HTC6525LVW using XDA Free mobile app
Hey thanks so much its working perfectly now :good:
I want to insert data to a database I have created. I have created an insert command at the OnCreate class. When viewing the database in SQLite Browser the data do not show. Can anyone help me
DatabaseHelper
Code:
package app.mobiledevicesecurity;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
* Created by Martin on 2015/07/28.
*/
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "mobilesec.db";
public static final String TABLE_NAME = "read_table";
public static final String COL_1 = "ID";
public static final String COL_2 = "CATEGORY";
public static final String COL_3 = "HEADING";
public static final String COL_4 = "INFO";
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1);
SQLiteDatabase db = this.getWritableDatabase();
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table " + TABLE_NAME + " (ID INTEGER PRIMARY KEY AUTOINCREMENT, CATEGORY TEXT, HEADING TEXT, INFO TEXT)");
ContentValues cv = new ContentValues();
cv.put(COL_2,"Malware");
cv.put(COL_3,"Virus");
cv.put(COL_4,"Harmfull for device");
db.insert(TABLE_NAME, null, cv);
}
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS "+TABLE_NAME);
onCreate(db);
}
}
MainActivity
Code:
package app.mobiledevicesecurity;
import android.content.Intent;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
public class MainActivity extends ActionBarActivity {
DatabaseHelper myDb;
private static Button readbtn;
private static Button quizbtn;
private static Button scoresbtn;
private static Button settingsbtn;
private static Button helpbtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myDb = new DatabaseHelper(this);
OnClickReadButtonListener();
OnClickQuizButtonListener();
OnClickScoresButtonListener();
OnClickSettingsButtonListener();
OnClickHelpButtonListener();
}
public void OnClickReadButtonListener() {
readbtn = (Button) findViewById(R.id.readbutton);
readbtn.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("app.mobiledevicesecurity.Read_Category");
startActivity(intent);
}
}
);
}
public void OnClickQuizButtonListener() {
quizbtn = (Button) findViewById(R.id.quizbutton);
quizbtn.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("app.mobiledevicesecurity.Quiz");
startActivity(intent);
}
}
);
}
public void OnClickScoresButtonListener() {
scoresbtn = (Button) findViewById(R.id.scoresbutton);
scoresbtn.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("app.mobiledevicesecurity.Scores");
startActivity(intent);
}
}
);
}
public void OnClickSettingsButtonListener() {
settingsbtn = (Button) findViewById(R.id.settingsbutton);
settingsbtn.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("app.mobiledevicesecurity.Settings");
startActivity(intent);
}
}
);
}
public void OnClickHelpButtonListener() {
helpbtn = (Button) findViewById(R.id.helpbutton);
helpbtn.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("app.mobiledevicesecurity.Help");
startActivity(intent);
}
}
);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
when I run the app on the emulator and open Android Device Monitor and get the database file and open it with SQlite Browser. Only the Column names are created the values are not shown. Why is this happening
Try to commit after you insert a record, also I think you can check what the insert command is returning to see if the insert command was successful or not...
The reason it isn't working is because you probably added the the insert after you had already created your database, so therefore onCreate is not being called anymore.
onUpgrade will only be called if you change the version of your database, so that will not be called either.
you should just make another method that is used to update your table, or explicitly call Oncreate.
what I did while I was testing is in the constructor of my database class, i would call a method that would drop all the tables, and then explicitly call onCreate after that. Remove this code when you are done testing
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() {
....
}
I want to send mail from Navigation Drawer using the intent. First, my MainActivity.
Code:
else if(id==R.id.nav_mail) {
fragment = new MailFragment();
}
and MailFragment.
Code:
public class MailFragment extends Fragment {
public MailFragment() {
Intent email = new Intent(Intent.ACTION_SEND);
email.setType("plain/text");
String[] address = {"********@gmail.com"};
email.putExtra(Intent.EXTRA_EMAIL, address);
email.putExtra(Intent.EXTRA_SUBJECT, "Subject___****");
email.putExtra(Intent.EXTRA_TEXT, "Text___****.\n\n");
startActivity(email);
}
// @Override
// public View onCreateView(LayoutInflater inflater, ViewGroup container,
// Bundle savedInstanceState) {
// TextView textView = new TextView(getActivity());
// textView.setText(R.string.hello_blank_fragment);
// return textView;
// }
}
Run to create crash. The reason why I used to use fragment is because I made the simple screen change function fragment.
If you need more code, comment plz.
I didn't get what you are trying to do. If you are trying to invoke the "Select your mail app" screen and then send a message thru the Intent all of this when the user clicks on a row on the drawer then you should just copy the code to
Code:
else if(id==R.id.nav_mail) {
// here
}
without switching any fragment.
By the way, as far as I know, the fragment's public constructor must be empty.
You cannot do it from Fragment's constructor. Move your code to onActivityCreated() method.
qlife1146 said:
I want to send mail from Navigation Drawer using the intent. First, my MainActivity.
Code:
else if(id==R.id.nav_mail) {
fragment = new MailFragment();
}
and MailFragment.
Code:
public class MailFragment extends Fragment {
public MailFragment() {
Intent email = new Intent(Intent.ACTION_SEND);
email.setType("plain/text");
String[] address = {"********@gmail.com"};
email.putExtra(Intent.EXTRA_EMAIL, address);
email.putExtra(Intent.EXTRA_SUBJECT, "Subject___****");
email.putExtra(Intent.EXTRA_TEXT, "Text___****.\n\n");
startActivity(email);
}
// @Override
// public View onCreateView(LayoutInflater inflater, ViewGroup container,
// Bundle savedInstanceState) {
// TextView textView = new TextView(getActivity());
// textView.setText(R.string.hello_blank_fragment);
// return textView;
// }
}
Run to create crash. The reason why I used to use fragment is because I made the simple screen change function fragment.
If you need more code, comment plz.
Click to expand...
Click to collapse
Creating a new Intent in the constructor is a really bad idea. An example from the android's developer guide
Code:
public class MainActivity extends AppCompatActivity {
public static final String EXTRA_MESSAGE = "com.example.myfirstapp.MESSAGE";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
/** Called when the user taps the Send button */
public void sendMessage(View view) {
Intent intent = new Intent(this, DisplayMessageActivity.class);
EditText editText = (EditText) findViewById(R.id.editText);
String message = editText.getText().toString();
intent.putExtra(EXTRA_MESSAGE, message);
startActivity(intent);
}
}