[TUTORIAL]Xposed module devlopment

Search This thread

dillonr

Senior Member
Apr 29, 2012
106
11
Oshawa
Is it possible to call/run another method (of the hooked application) when the application is loaded?
I am using tasker to open up my music playing app (grooveshark) when i enter my car, but i was going to make grooveshark start playing automatically when tasker opens it, so that i do not have to remove my phone from my pockets to start the music.
I would need to call
Code:
com.grooveshark.android.lib.player.AsyncPlayer.play
and pass the argument
Code:
(boolean) true
to hopefully get it to start playing

Any input would be appreciated

Edit:
XposedHelpers.callMethod() looks promising
 
Last edited:

S0bes

Senior Member
Jan 1, 2012
870
969
Hi, I got a question about this thing:
Code:
if (!resparam.packageName.equals("name.of.package"))
		        return;

How can I use it for different packages simultaneously ?
For example, I got this code
Code:
public void handleInitPackageResources(InitPackageResourcesParam resparam) throws Throwable {
	   			
		XSharedPreferences pref = new XSharedPreferences("com.s0bes.checkboxes", "settings");		
		H_on=pref.getBoolean("Disabled_data_icon", false);
		H_data=pref.getBoolean("Data_icon_H", false);
		Fm_speaker=pref.getBoolean("Speaker", false);		
			   
		
		// systemUi
		 if (!resparam.packageName.equals("com.android.systemui"))
		        return;	   
		   if (H_on==true)
	        resparam.res.setReplacement("com.android.systemui", "bool", "show_data_disabled_icon", true);
		  else
		  	resparam.res.setReplacement("com.android.systemui", "bool", "show_data_disabled_icon", false);
		   
		   if (H_data==true){
		        resparam.res.setReplacement("com.android.systemui", "bool", "config_hspa_data_distinguishable", true);
		        resparam.res.setReplacement("com.android.systemui", "bool", "config_hspap_data_distinguishable", true);}
			    else{
			    	resparam.res.setReplacement("com.android.systemui", "bool", "config_hspa_data_distinguishable", false);
			    	resparam.res.setReplacement("com.android.systemui", "bool", "config_hspap_data_distinguishable", false);}
		 
		   
		   //Fmradio 
		   if (!resparam.packageName.equals("com.motorola.android.fmradio"))		    
		        return;	 
		    if (Fm_speaker==true)
	        resparam.res.setReplacement("com.motorola.android.fmradio", "bool", "config_speaker_supported_in_fm_radio", true);
		    else
		    resparam.res.setReplacement("com.motorola.android.fmradio", "bool", "config_speaker_supported_in_fm_radio", false);   
		    
	}
and Fmradio part is not working :(

UPD:
Solved my problem. Saw how to do it in Gravitybox sources https://github.com/C3C0/GravityBox/blob/master/src/com/ceco/gm2/gravitybox/GravityBox.java
Code:
public void handleInitPackageResources(InitPackageResourcesParam resparam) throws Throwable {

		// if (!resparam.packageName.equals("com.android.systemui"))		
			 XposedSystemUI.initResources(resparam);
			 
		//if (!resparam.packageName.equals("com.motorola.android.fmradio"))		     	
				xposedRadio.initResources(resparam);
}
}
 
Last edited:
  • Like
Reactions: frkhtc

S0bes

Senior Member
Jan 1, 2012
870
969
Tutorial 9 - Methods with parameters

In an earlier tutorial, we covered hooking methods. But what if a method wants a parameter too?

Say if i want to hook onCreate(Bundle savedInstances) in com.android.settings

If i hook it using

Code:
findAndHookMethod("com.android.settings.Settings", lpparam.classLoader, "onCreate", new XC_MethodHook() {
            
 });

It will throw a methodNotFound error. So we need to specify the parameters. The method wants a Bundle object. So add Bundle.class as a parameter

Code:
findAndHookMethod("com.android.settings.Settings", lpparam.classLoader, "onCreate", [B]Bundle.class[/B], new XC_MethodHook() {
            
 });

Now lets pretend Bundle.class isnt in the SDK and is a system class so cant be referenced. I would use a String instead:

"android.os.Bundle"

Code:
findAndHookMethod("com.android.settings.Settings", lpparam.classLoader, "onCreate", [B]"android.os.Bundle"[/B], new XC_MethodHook() {
            
 });
@hamzahrmalik Can you tell me what should I use if parameter is a char?
Code:
@Override
 public boolean isValidDialpadAlphabeticChar(char ch) {
       return (ch >= 'a' && ch <= 'z');
    }
I tried
Code:
XposedHelpers.findAndHookMethod("com.android.dialer.dialpad.LatinSmartDialMap", loadpkg.classLoader,
                    "isValidDialpadAlphabeticChar", Character.class, new XC_MethodHook() {

                @Override protected void beforeHookedMethod(final MethodHookParam param) throws Throwable {
                    XposedBridge.log( "AAAAAAAAAAAAA" ); 
                }             
            });
But log says that it cant find isValidDialpadAlphabeticChar method
java.lang.NoSuchMethodError: com.android.dialer.dialpad.LatinSmartDialMap#isValidDialpadAlphabeticChar(java.lang.Character)#exact
at de.robv.android.xposed.XposedHelpers.findMethodExact(XposedHelpers.java:179)
at de.robv.android.xposed.XposedHelpers.findAndHookMethod(XposedHelpers.java:129)
at de.robv.android.xposed.XposedHelpers.findAndHookMethod(XposedHelpers.java:136)
 
Last edited:

hamzahrmalik

Senior Member
May 31, 2013
1,658
2,020
@hamzahrmalik Can you tell me what should I use if parameter is a char?
Code:
@Override
 public boolean isValidDialpadAlphabeticChar(char ch) {
       return (ch >= 'a' && ch <= 'z');
    }
I tried
Code:
XposedHelpers.findAndHookMethod("com.android.dialer.dialpad.LatinSmartDialMap", loadpkg.classLoader,
                    "isValidDialpadAlphabeticChar", Character.class, new XC_MethodHook() {

                @Override protected void beforeHookedMethod(final MethodHookParam param) throws Throwable {
                    XposedBridge.log( "AAAAAAAAAAAAA" ); 
                }             
            });
But log says that it cant find isValidDialpadAlphabeticChar method
java.lang.NoSuchMethodError: com.android.dialer.dialpad.LatinSmartDialMap#isValidDialpadAlphabeticChar(java.lang.Character)#exact
at de.robv.android.xposed.XposedHelpers.findMethodExact(XposedHelpers.java:179)
at de.robv.android.xposed.XposedHelpers.findAndHookMethod(XposedHelpers.java:129)
at de.robv.android.xposed.XposedHelpers.findAndHookMethod(XposedHelpers.java:136)

Your hook is fine, i think it's because its overrided method
I'm not sure what to do, ask on the xposed general forum (make sure it hasn't already been asked)
 

frkhtc

Senior Member
Aug 6, 2014
146
48
Solved my problem. Saw how to do it in Gravitybox sources https://github.com/C3C0/GravityBox/blob/master/src/com/ceco/gm2/gravitybox/GravityBox.java
Code:
public void handleInitPackageResources(InitPackageResourcesParam resparam) throws Throwable {

		// if (!resparam.packageName.equals("com.android.systemui"))		
			 XposedSystemUI.initResources(resparam);
			 
		//if (!resparam.packageName.equals("com.motorola.android.fmradio"))		     	
				xposedRadio.initResources(resparam);
}
}

How did you do that? Sorry for my noobness :D
 

frkhtc

Senior Member
Aug 6, 2014
146
48
Thanks for this tutorial hamzahrmalik. I manage to make a module to change some drawables from framework, for a specific app.
Now, since i'm a total noob on Java programming, can someone give me a tip on how to change those files, for multiple specific apps.
An example: if a open Dialer, it should use png1, if i open messages it should use png2 and so on.
I have tried an if-else statement but doesn't work
@Override
public void handleInitPackageResources( XC_InitPackageResources.InitPackageResourcesParam resparam) throws Throwable {

//contacts
if (!resparam.packageName.equals("com.android.htccontacts")) {

XModuleResources modRes = XModuleResources.createInstance(MODULE_PATH, resparam.res);
XposedBridge.log("---------------------CONTACTS------------------------------");
XResources.setSystemWideReplacement("com.htc", "drawable", "common_app_bkg_top_src", modRes.fwd(R.drawable.common_app_bkg_top_blue));
XResources.setSystemWideReplacement("com.htc", "drawable", "common_footer", modRes.fwd(R.drawable.common_footer));
XResources.setSystemWideReplacement("com.htc", "drawable", "common_header", modRes.fwd(R.drawable.common_headerblue));
XposedBridge.log("sensesixtheme: ----------Contacts were changed!--------------");
}
//gallery
else if (!resparam.packageName.equals("com.htc.album")) {
XModuleResources modRes = XModuleResources.createInstance(MODULE_PATH, resparam.res);
XposedBridge.log("sensesixtheme: ---------------------------GALLERY-----------------------------------------------");
XResources.setSystemWideReplacement("com.htc", "drawable", "common_app_bkg_top_src", modRes.fwd(R.drawable.common_app_bkg_top_red));
XResources.setSystemWideReplacement("com.htc", "drawable", "common_footer", modRes.fwd(R.drawable.common_footer));
XResources.setSystemWideReplacement("com.htc", "drawable", "common_header", modRes.fwd(R.drawable.common_headerred));
XposedBridge.log(" ---------------Ok, gallery were changed!----------------");
}
 

hamzahrmalik

Senior Member
May 31, 2013
1,658
2,020
Thanks for this tutorial hamzahrmalik. I manage to make a module to change some drawables from framework, for a specific app.
Now, since i'm a total noob on Java programming, can someone give me a tip on how to change those files, for multiple specific apps.
An example: if a open Dialer, it should use png1, if i open messages it should use png2 and so on.
I have tried an if-else statement but doesn't work
@Override
public void handleInitPackageResources( XC_InitPackageResources.InitPackageResourcesParam resparam) throws Throwable {

//contacts
if (!resparam.packageName.equals("com.android.htccontacts")) {

XModuleResources modRes = XModuleResources.createInstance(MODULE_PATH, resparam.res);
XposedBridge.log("---------------------CONTACTS------------------------------");
XResources.setSystemWideReplacement("com.htc", "drawable", "common_app_bkg_top_src", modRes.fwd(R.drawable.common_app_bkg_top_blue));
XResources.setSystemWideReplacement("com.htc", "drawable", "common_footer", modRes.fwd(R.drawable.common_footer));
XResources.setSystemWideReplacement("com.htc", "drawable", "common_header", modRes.fwd(R.drawable.common_headerblue));
XposedBridge.log("sensesixtheme: ----------Contacts were changed!--------------");
}
//gallery
else if (!resparam.packageName.equals("com.htc.album")) {
XModuleResources modRes = XModuleResources.createInstance(MODULE_PATH, resparam.res);
XposedBridge.log("sensesixtheme: ---------------------------GALLERY-----------------------------------------------");
XResources.setSystemWideReplacement("com.htc", "drawable", "common_app_bkg_top_src", modRes.fwd(R.drawable.common_app_bkg_top_red));
XResources.setSystemWideReplacement("com.htc", "drawable", "common_footer", modRes.fwd(R.drawable.common_footer));
XResources.setSystemWideReplacement("com.htc", "drawable", "common_header", modRes.fwd(R.drawable.common_headerred));
XposedBridge.log(" ---------------Ok, gallery were changed!----------------");
}

In your if statements you've used
If(!reparam.bla.bla)
The ! Means not equal
Remove all the !

Sent from my amazingly awesome OnePlus One using Tapatalk
 
  • Like
Reactions: frkhtc

frkhtc

Senior Member
Aug 6, 2014
146
48
In your if statements you've used
If(!reparam.bla.bla)
The ! Means not equal
Remove all the !

Sent from my amazingly awesome OnePlus One using Tapatalk

Thanks a lot. It's working now. There is a lag of 0.5 sec in changing those files, but not in every app. Gonna do some research. For now i can live with that.
 

frkhtc

Senior Member
Aug 6, 2014
146
48
I'm back with another question. How can you change the status bar background in an app?
i have tried this code
Code:
if (resparam.packageName.equals("com.android.htccontacts")) try {
            		resparam.res.setReplacement("com.htc", "drawable", "common_header", modRes.fwd(R.drawable.header_default_categone));
            		resparam.res.setReplacement("com.android.systemui", "drawable", "status_bar_background", new XResources.DrawableLoader() {
            		    @Override
            		    public Drawable newDrawable(XResources res, int id) throws Throwable {
            		        return new ColorDrawable(Color.WHITE);
            		    }
            		});
            	} catch (Throwable t) { XposedBridge.log(t); }
but it gives this error in logcat: android.content.res.Resources$NotFoundException: com.android.systemui:drawable/status_bar_background
at android.content.res.XResources.setReplacement(XResources.java307)
 

Mjuksel

Senior Member
Jan 2, 2011
847
240
38
www.mjxl.net
edit scrap my old post ;

this is what i have next, trying to make the notifications transparent.. not really working

Code:
package mjxl.xposed.cm11;

import android.content.res.XModuleResources;
import de.robv.android.xposed.IXposedHookInitPackageResources;
import de.robv.android.xposed.IXposedHookZygoteInit;
import de.robv.android.xposed.callbacks.XC_InitPackageResources.InitPackageResourcesParam;

public class CM11notifications implements IXposedHookZygoteInit, IXposedHookInitPackageResources {
    private static String MODULE_PATH = null;

    @Override
    public void initZygote(StartupParam startupParam) throws Throwable {
        MODULE_PATH = startupParam.modulePath;
    }

    @Override
    public void handleInitPackageResources(InitPackageResourcesParam resparam) throws Throwable {
        XModuleResources modRes = XModuleResources.createInstance(MODULE_PATH, resparam.res);
        resparam.res.setReplacement("android", "drawable", "notification_bg_normal", modRes.fwd(R.drawable.mjxlnull));
    }
}

this doesn't give any errors, but either i'm pointing the wrong files, or something needs a fix.

any tips ?
 
Last edited:

hamzahrmalik

Senior Member
May 31, 2013
1,658
2,020
edit scrap my old post ;

this is what i have next, trying to make the notifications transparent.. not really working

Code:
package mjxl.xposed.cm11;

import android.content.res.XModuleResources;
import de.robv.android.xposed.IXposedHookInitPackageResources;
import de.robv.android.xposed.IXposedHookZygoteInit;
import de.robv.android.xposed.callbacks.XC_InitPackageResources.InitPackageResourcesParam;

public class CM11notifications implements IXposedHookZygoteInit, IXposedHookInitPackageResources {
    private static String MODULE_PATH = null;

    @Override
    public void initZygote(StartupParam startupParam) throws Throwable {
        MODULE_PATH = startupParam.modulePath;
    }

    @Override
    public void handleInitPackageResources(InitPackageResourcesParam resparam) throws Throwable {
        XModuleResources modRes = XModuleResources.createInstance(MODULE_PATH, resparam.res);
        resparam.res.setReplacement("android", "drawable", "notification_bg_normal", modRes.fwd(R.drawable.mjxlnull));
    }
}

this doesn't give any errors, but either i'm pointing the wrong files, or something needs a fix.

any tips ?
I'm assuming you're targeting wrong
Look at some mods on github which change notification background

Sent from my amazingly awesome OnePlus One using Tapatalk
 

devtrop

Member
Sep 28, 2014
5
0
how can I hook a systemService?

I'm trying to hook AppOpsService,
actually, I'm not even sure what is the correct package name...
I'd like to hook the getUid() method so I could filter out some uid from the AppOps...

Is it possible to hook a method in a system service?
 
Oct 23, 2014
46
3
Bluetooth Launcher APK to launch voice dialer in LG g2

Hello Hamzahrmalik,

I was the onewho requested for the Hijiri clock and I must say it is fantastic in all aspect . I am using it in my LG G2 D 802 successfully. I want to send donation to your development project, but I don't know how to send it. Kindly give the address by which I can send it by PayPal.

I have one more request. I am very much satisfied with my LG G2 D802. The only problem is that it can not launch any voice dialer applications like Cyberon voice speed dial, Google search, or Utter when the dial button of the connected bluetooth head set is pressed. I can answer the call by pressing it , but can't make a call. I wrote to the company about this which is available even in the old and basic models like Nokia N 95. But they said it is not there in the LG g2. Then I came across Cloudyfa's Cloudyflex 2.2 rom for LG g2. When I installed it, it brought back this function, and I can launch Cyberon voice speed dial by pressing the Bluetooth dial button. But when they upgraded the rom, this function again lost, so that now I am stuck in Cloudyflex 2.2 rom only to retain this function. The bluetooth version in this rom is F340k20a.
I tried to extract the apk file, odex file , lib file etc and tried to replace in higher versions of the same rom and other roms, but failed.
Now I want to install the ported G3 rom in my LG G2, but none of them has this bluetooth function.
I humbly request you ,if possible make an apk, or a xposed module by which you can assign any third party voice dialer to be launched when the dial button of bluetooth head set is pressed. Without this the phone will not be completely Hands free . Always we have to mount the phone in the dash board ofthe car and shout at it to open Google now. So it will be a great apk or module if you can successfully make it and we can install it any android with all latest roms.
Kindly try for it, and we don't mind even if it is a paid apk

Thanking You
Dr.Saidalavi
 

hamzahrmalik

Senior Member
May 31, 2013
1,658
2,020
Hello Hamzahrmalik,

I was the onewho requested for the Hijiri clock and I must say it is fantastic in all aspect . I am using it in my LG G2 D 802 successfully. I want to send donation to your development project, but I don't know how to send it. Kindly give the address by which I can send it by PayPal.

I have one more request. I am very much satisfied with my LG G2 D802. The only problem is that it can not launch any voice dialer applications like Cyberon voice speed dial, Google search, or Utter when the dial button of the connected bluetooth head set is pressed. I can answer the call by pressing it , but can't make a call. I wrote to the company about this which is available even in the old and basic models like Nokia N 95. But they said it is not there in the LG g2. Then I came across Cloudyfa's Cloudyflex 2.2 rom for LG g2. When I installed it, it brought back this function, and I can launch Cyberon voice speed dial by pressing the Bluetooth dial button. But when they upgraded the rom, this function again lost, so that now I am stuck in Cloudyflex 2.2 rom only to retain this function. The bluetooth version in this rom is F340k20a.
I tried to extract the apk file, odex file , lib file etc and tried to replace in higher versions of the same rom and other roms, but failed.
Now I want to install the ported G3 rom in my LG G2, but none of them has this bluetooth function.
I humbly request you ,if possible make an apk, or a xposed module by which you can assign any third party voice dialer to be launched when the dial button of bluetooth head set is pressed. Without this the phone will not be completely Hands free . Always we have to mount the phone in the dash board ofthe car and shout at it to open Google now. So it will be a great apk or module if you can successfully make it and we can install it any android with all latest roms.
Kindly try for it, and we don't mind even if it is a paid apk

Thanking You
Dr.Saidalavi
Firstly, this should go in the requests thread
Have you tried using the Xposed Additions module it let's you remap buttons

Edit
I don't take donations, you can help out by buying any of my paid apps, thanks

Sent from my amazingly awesome OnePlus One using Tapatalk
 

vikasb32

Recognized Themer
May 9, 2011
2,057
1,999
Hardwar
OnePlus 6
hello i have problem my xposed module work fine but when i use setTheme function my module didn't work at all hope you will help me in this. here is my code

this is my fragment class

public class SettingFragment extends PreferenceFragment implements
OnSharedPreferenceChangeListener {

public static boolean enabled = false;



@Override
public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
this.getPreferenceManager().setSharedPreferencesMode(
PreferenceActivity.MODE_WORLD_READABLE);
this.getPreferenceManager().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);

this.addPreferencesFromResource(R.xml.pref_setting);



}


@Override
public void onSharedPreferenceChanged(SharedPreferences arg0, String key) {

//SettingsProvider.settingsChanged(getActivity());
if (key.equals("theme")) {

Intent intent = new Intent(getActivity(), SettingActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
getActivity().overridePendingTransition(android.R.anim.fade_in,
android.R.anim.fade_out);


}
}

}

here my main activity the red color code make my module not to work at all but if i remove that code it work fine.

public class SettingActivity extends ActionBarActivity {
private Menu Vmenu;
private SharedPreferences prefs;
@Override
public void onCreate(Bundle savedInstanceState) {
prefs = PreferenceManager.getDefaultSharedPreferences(this);
// PreferenceManager.setDefaultValues(this, R.xml.pref_setting, false);
if (prefs.getBoolean(Common.KEY_APP_THEME, false)) {


setTheme(R.style.AppTheme);
}
else {
setTheme(R.style.AppBaseTheme);
}


super.onCreate(savedInstanceState);

if(savedInstanceState == null) {
setContentView(R.layout.activity_settings);
Fragment fragment = new SettingFragment();
fragment.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction().add(R.id.settingsFragment, fragment).commit();
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
SystemBarTintManager tintManager = new SystemBarTintManager(this);
tintManager.setStatusBarTintEnabled(true);
int actionBarColor = this.getResources().getColor(
R.color.statusbar_color);
tintManager.setStatusBarTintColor(actionBarColor);
}
}

public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
Vmenu = menu;
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);

return true;
}

public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.toast:
final Toast tag = Toast.makeText(getApplicationContext(),
R.string.toast_test_title, Toast.LENGTH_SHORT);
tag.show();
return true;
}

return super.onOptionsItemSelected(item);
}




}
 

hamzahrmalik

Senior Member
May 31, 2013
1,658
2,020
hello i have problem my xposed module work fine but when i use setTheme function my module didn't work at all hope you will help me in this. here is my code

this is my fragment class



here my main activity the red color code make my module not to work at all but if i remove that code it work fine.
What's the module meant to do?
Where is the Xposed class?
The red is in your activity not the module part and therefore not an Xposed error

Sent from my amazingly awesome OnePlus One using Tapatalk
 
  • Like
Reactions: vikasb32

vikasb32

Recognized Themer
May 9, 2011
2,057
1,999
Hardwar
OnePlus 6
My module is Xtoast and no problem in xposed class but when I copy red code in my to add a functionality to change app theme to holo dark and light my xposed did not work at all but when I remove that red part my module work fine can you tell me why? It is due to xsharedpreference did not able to read my preference file?
 

hamzahrmalik

Senior Member
May 31, 2013
1,658
2,020
My module is Xtoast and no problem in xposed class but when I copy red code in my to add a functionality to change app theme to holo dark and light my xposed did not work at all but when I remove that red part my module work fine can you tell me why? It is due to xsharedpreference did not able to read my preference file?
Ah I get you
Yes it is you need to use world readable

Sent from my amazingly awesome OnePlus One using Tapatalk
 

Top Liked Posts

  • There are no posts matching your filters.
  • 118
    Iv'e recently started a blog on Xposed Module development. It goes through the basics for a beginner and explains in as much detail as possible. You can find it here

    http://xposedtutorial.blogspot.co.uk/p/tutorial-1-setting-up.html


    Edit: I've now decided to keep the tutorial on XDA. I might also keep a copy on the blog, not sure yet

    P.S: A lot of this tutorial is based on the original development tutorial which can be found here, credits to rovo89

    Tutorial 1 - Setting up

    There are a few requirements for making an Xposed Module.
    *Eclipse, or Java IDE of your choice, with Android SDK and devlopment enviornment set up. I'm not going to cover that in this tutorial
    *Knowledge of Java programming language
    *An android phone which supports Xposed, with Xposed installed and working for testing on
    *Some knowledge of Android development
    *Time
    *An idea of course

    For the purpose of this tutorial, we will be creating two modules (using two different features of the xposed bridge). The first will replace the clock in the status bar with a smiley face. The second will change the height of the navigation bar. I will be using Eclipse or Android Studio in this tutorial.

    Eclipse

    NEW: this tool will setup the project for you! http://xdaforums.com/showthread.php?t=2712825


    Firstly you must set up an Android project as normal. For the target API, use the latest available. Name the project Smiley Clock, and choose a package name.

    We won't need an Activity for this module, so don't create one

    1.png

    2.png


    Android Studio


    Firstly you must set up an Android project as normal. For the target API, use the latest available. Name the project Smiley Clock, and choose a package name.

    We won't need an Activity for this module, so don't create one



    OK, that's the project created. Now we need to make Xposed recognize this as a module. Add the following meta tags to your Android Manifest, within the Application tag

    Code:
    <meta-data
                android:name="xposedmodule"
                android:value="true" />
            <meta-data
                android:name="xposedminversion"
                android:value="30" />
            <meta-data
                android:name="xposeddescription"
                android:value="Add a smiley face" />

    3.png


    At this point you can run the application on your test device. It should show up in the Xposed Installer app as a module. Check the box to enable your module and reboot your device. Of course, the module won't do anything yet!

    A good idea at this point would be to add a new filter to your logcat to track error messages from Xposed.

    Studio: Go on Android Monitor (along bottom). Make a new filter and filter by tag name. The tag is "xposed"
    Eclipse:

    Add a filter named "Xposed" and filter by the tag name "Xposed"
    (picture is for Eclipse)
    4.png


    You will now see messages from the Xposed Framework

    5.png


    There will be an error for your module about xposed_init file, don't worry, getting to that!

    Make a new package (same as package name we used when making the Android Project) and within that package make a class. Call it anything, I'll call mine Main.

    6.png


    Secondly add the XposedBridge API jar. This can be found on this thread on XDA. Add the jar to the root directory of the project, NOT the lib directory.
    Eclipse: Right click - build path - add to build path. Do not export it in the Order and Export tab.

    Studio: Right click, add as library. Then go in gradle files and find build.gradle for the app module. Find the dependency which looks something like this
    compile files('src/main/java/com/hamzahrmalik/xposedtutorial/XposedBridgeApi-54.jar')
    and change the "compile" to "provided" so it is like
    provided files('src/main/java/com/hamzahrmalik/xposedtutorial/XposedBridgeApi-54.jar')

    Now create a file in the assets directory called xposed_init.
    Studio users:
    First you will need to make the assets directory. I think the easiest way is to first switch to "project files" view at the top of the navigation pane as shown below. Then create a folder inside src/main called assets. Then place the xposed_init in the assets folder.

    Inside this file, type:

    packagename.classname

    where packname is the name of your package and class name is the name of your class. So in my case I will type

    com.hamzah.smileyclock.Main

    This tells Xposed where to look for the code for the module. You file tree should now look like this

    7.png


    Now the project is set up. In the next tutorial, we will look at how Xposed works, this will help you understand how to make modules.

    Tutorial 2 - Brief introduction to how Xposed works

    This tutorial is not really a true tutorial (gasp!). It will outline some basic features of Xposed which will help you understand future tutorials.
    Xposed allows a developer to access and modify the code for system applications. For example, one useful feature is the "find and hook" feature. This allows a developer to find a method inside another application and add their own code after it. So you could find the method in the Android source code that alerts the user when the wrong pattern is entered, and then instruct the system to hook onto that method and edit the alert to say something else. Another thing that Xposed allows us to do is replace resources. This includes Strings dimensions, drawables and much more. So we could edit the dimension of the navigation bar height (which we will in later tutorials) by replacing the resource which tells it what height to be.

    The next tutorial, we will start exploring the Android code and see what methods to hook to replace the clock with a smiley face!

    Tutorial 3 - Exploring the target and modifying it

    Ok so at this point, you should have an Xposed mod thatdoes nothing. The next step is to work out exactly what we want it to do! We want it to edit the clock, by hooking the method (read the last tutorial for more informtion on this). So the first step is to find that method.

    So visit http://grepcode.com/project/repository.grepcode.com/java/ext/com.google.android/android/ in your browser to view Android's source code. If (in Android 4+) you browse to com.android.systemui.statusbar.policy.Clock.java
    you will find the class that controls the clock. In here, there is a handy method called updateClock() which ppears to be controlling what gets written to the TextView in the statusbar (this whole class extends TextView). Now if you know how to make Android apps (which you should) you will be familiar with TextView. We can manipulate this TextView by changing colour, text, font, size etc, as you could with a TextView in a normal Android app.

    Of course this was easy, but depending on exactly what you want your module to do, you may have to hook many methods. If you've ever modded APK's, you'll know what i mean ;)

    This was another short tutorial, in the next one we will start coding the module

    Tutorial 4 - The Code

    In this tutorial we can finally get to some code. Exciting right?
    OK so we now have the following information
    *We can hook methods using Xposed
    *There happens to be a method which writes text to the clock
    *We can hook this method to edit the text

    So first of all, fire up your eclipse workspace and have you Xposed class implement IXposedHookLoadPackage
    Then add unimplemented methods.
    Your class should now look like:

    Code:
    package com.hamzah.smileyclock;
    
    import de.robv.android.xposed.IXposedHookLoadPackage;
    import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
    
    public class Main implements IXposedHookLoadPackage {
    
     @Override
     public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
      
     }
    
    }

    The method that we are overriding gets called every time the user or system opens an app. We can use the parameter of the method to check when systemui gets loaded, then hook into it and modify the clock. Easy right?

    Add this inside your method

    Code:
    if (!lpparam.packageName.equals("com.android.systemui"))//check if the package being loaded is systemUI
                return;
    //All code here is only called if it is indeed SystemUI
    So now we need our hook, add this code after the return:
    Code:
    findAndHookMethod("com.android.systemui.statusbar.policy.Clock", lpparam.classLoader, "updateClock", new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                 
                }
     });

    NOTE: this will only work because updateClock doesn't need any parameters. If the method you want to hook does, see tutorial 9

    You must also add the following imports statements

    Code:
    import de.robv.android.xposed.IXposedHookLoadPackage;
    import de.robv.android.xposed.XC_MethodHook;
    import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
    import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;

    Explanation: The findAndHookMethod is hooking onto com.android.systemui.statusbar.policy.Clock
    The afterHookedMethod allows us to add our own code after the system method is executed, so in this case, the code to add a smiley face will go here. The MethodHookParam allows us to modify the TextView of the method we are hooking. So we need to get hold of that TextView, add this code

    Code:
    TextView tv = (TextView) param.thisObject;

    This is the TextView containing the clock, whatever we do with this TextView at this point, will happen to the TextView in the statusbar, So now simply add

    Code:
    tv.setText(":)");

    This will replace the clock with a smiley face. Alternatively, use

    Code:
    tv.appendText(":)");

    to keep the time and add the smiley after it

    Now deploy the app to your test device, and reboot. You should see a smiley face in place of the clock!

    Full Code

    Code:
    package com.hamzah.smileyclock;
    
    import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
    import android.widget.TextView;
    import de.robv.android.xposed.IXposedHookLoadPackage;
    import de.robv.android.xposed.XC_MethodHook;
    import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
    
    public class Main implements IXposedHookLoadPackage {
    
     @Override
     public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
      if (!lpparam.packageName.equals("com.android.systemui"))
                return;
      
       findAndHookMethod("com.android.systemui.statusbar.policy.Clock", lpparam.classLoader, "updateClock", new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                 TextView tv = (TextView) param.thisObject;
                 tv.setText(":)");
                 
                }
     });
     }
    }

    That's it for SmileyClock, in the next tutorial, we will look at another feature of Xposed, that is, replacing resources, and will enable/disable the screen wake up on unplug and also edit the height of the system navigation bar.

    Tutorial 5 - Replacing Resources

    Xposed allows us to replace resources such as String, int, boolean, dimen, or even drawables. In this tutorial we will enable/disable screen wake-up on unplug and in the next one, replace the dimen of navigation bar height and width to make it half size. Simple resources like int and String can be replaced by passing the new value as a parameter but more complex ones like drawable and dimen must be referenced from your own resources. Don't worry, I'll explain it all!

    First, we will replace a boolean which tells the system whether or not to wake the screen on unplug. There is a boolean in the framework-res.apk (found in /system/framework) which tells the system this information. We can used Xposed to edit this value, without touching the APK. My phone's default is false so I'm going to make it true, if yours is already true, make it false to make it more noticeable. In a future tutorial, when we learn saving preferences, we will add the ability for the user to set the value. For now, it will be hard coded.

    Firstly set up a new project as in tutorial 1. Call it anything. Again, no activity or icon required, though you might want an icon anyway.

    Have your class implement IXposedHookZygoteInit

    and add unimplemented methods. This is called before anything else and we will use it for replacing our resource.

    Add this code inside the initZygote method
    Code:
    XResources.setSystemWideReplacement("android", "bool", "config_unplugTurnsOnScreen", false);

    android is the package name of framework-res, bool is the type of resource (boolean) "config_unplugTurnsOnScreen" is the variable we are replacing and false is the new value.

    Now when you run this module, enable and reboot, you should find that if you plug in a charger, turn off the screen, and unplug it, nothing will happen. If you were to change it to TRUE instead of FALSE, when you unplugged, it would wake the screen.

    In the text tutorial, we will replace the navigation bar height

    Tutorial 6 - Complex Resources

    In this tutorial we will change the height of the navigation bar to 36dp, normal is 48dp. Much is the same as last time, but there are a few differences. Once again, set up a new project. Have your module class implement IXposedHookZygoteInit once again. Also implement IXposedHookInitPackageResources
    Add the unimplemented methods.

    Make a new variable inside the initZygote method:
    Code:
    String MODULE_PATH = startupParam.modulePath;

    In the handleInitPackageResources method, add
    Code:
    if (!resparam.packageName.equals("android"))
    	         return;

    Now we know we are in the right package

    Add:

    Code:
    XModuleResources modRes = XModuleResources.createInstance(MODULE_PATH, resparam.res);

    Use CTRL-SHIFT-O in Eclipse to import the necessary packages.

    Next we need a dimen resource to forward as the height of the navigation bar. Make a new XML files inside /values called dimens.xml. Add this inside it

    Code:
        36dp

    Now all that's left is to forward this to be used. Add this code inside handleInitPackageResources

    Code:
    XResources.setSystemWideReplacement("android", "dimen", "navigation_bar_height", modRes.fwd(R.dimen.navigationbarSize));
    The first 3 parameters are the same as the ones in tutorial 5. The last one has the same function as in the las tutorial, but rather than passing a variable, we are forwarding a resource. This could also be done with drawables, I once made a module to replace all buttons on the navigation bar with the ones found on Xperia ROM's.

    At this point, when you deploy the module, enable it and reboot, your navigation bar should be noticeably smaller.

    In the next tutorial we will look at creating and user interfaces and saving data in ways that both interface and module can read and write to. We will be using the mod we made in tutorial 4, and allow the user to define text rather than have a smiley face.

    Tutorial 7 - User Interfaces and Preferences

    Open up the SmileyClock we made in Tutorial 4. We did not make an Activity so make one now, File>New>Android Activity. Make sure you make it a Launcher Activity. We need to widgets in our UI, a textbox and an Apply button. I'm not going to cover making these, just make sure you have a method called when the button is pressed. Make the EditText id "input" so it will be easier to follow the tutorial because that is what i am making mine.

    When the apply button is pressed in my case this method is called
    Code:
    public void apply(){
    EditText et = (EditText) findViewById(R.id.input);
    String input = et.getText().toString();
    }

    So now I have the user input as a String, I need to save it. Use Android SharedPreferences for this,

    Code:
    SharedPreferences pref = getSharedPreferences("user_settings", MODE_WORLD_READABLE);

    The mode world readable is crucial to allow the Xposed Module to read it, otherwise you will get permission denied. Now get the Editor and save this string as "user_text",
    Code:
    Editor editor = pref.edit();
    editor.putString("user_text", input);

    Now it is saved, we need the Xposed Module to read it. Switch back to the class containing the Xposed Module, the one we made in tutorial 4. Find this line:
    Code:
    tv.setText(":)");

    Instead, replace it with this
    Code:
    XSharedPreferences pref = new XSharedPreferences("com.hamzah.smileyclock", "user_settings");
    //Gets the shared preference 
    String text = pref.getString("user_text", "");
    //reads the value which is saves, using nothing as default value to use if nothing is saved
    tv.setText(text);
    //sets the text to saved value

    When you deploy this and set some text, that text should then appear in the status bar after the clock. Note that when you save this value, it will not change in the statusbar until you restart SystemUI. It might change when time changes, not sure.

    In the next tutorial we will cover modifying layouts

    Tutorial 8 - Modifying Layouts

    Xposed lets us modify layouts in other apps. In this tutorial, we will modify the navigation bar with various tweaks. Firstly we will make the background blue. So make a new Xposed Project and have your module class implement IXposedHookInitPackageResources. This gives is a parameter that can be used for modifying layouts. Add the unimplemented method and add this code inside the method

    Code:
     resparam.res.hookLayout("com.android.systemui", "layout", "navigation_bar", new XC_LayoutInflated() {
    	        @Override
    	        public void handleLayoutInflated(LayoutInflatedParam liparam) throws Throwable {
    	        	
    	        }
    	    });
    com.android.systemui is the package name for the app containing the navigation bar View, layout is the type of resource, navigation_bar is the View name as defined in /res/layout (of SystemUI.apk). Now we need to get a View object for the navigation bar. Add this code inside the overriden method

    Code:
             @Override
    	 public void handleLayoutInflated(LayoutInflatedParam liparam) throws Throwable {
             View navbar = (View) liparam.view.findViewById(
    	                    liparam.res.getIdentifier("nav_buttons", "id", "com.android.systemui"));
         }

    We have gotten the view using the findViewById method, and passing in the ids. We know the id is "nav_buttons" because if we look at /res/layouts/navigation_bar.xml in SystemUI.apk, we see this

    Code:
    <?xml version="1.0" encoding="utf-8"?>
    <com.android.systemui.statusbar.phone.NavigationBarView android:background="#ff000000" android:layout_width="fill_parent" android:layout_height="fill_parent"
      xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui">
        <FrameLayout android:id="@id/rot0" android:layout_width="fill_parent" android:layout_height="fill_parent">
            <LinearLayout android:orientation="horizontal" android:id="@id/nav_buttons" android:clipChildren="false" android:clipToPadding="false" android:layout_width="fill_parent" android:layout_height="fill_parent" android:animateLayoutChanges="true">
                <View android:visibility="invisible" android:layout_width="40.0dip" android:layout_height="fill_parent" android:layout_weight="0.0" />
                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@id/back" android:layout_width="80.0dip" android:layout_height="fill_parent" android:src="@drawable/ic_sysbar_back" android:layout_weight="0.0" android:contentDescription="@string/accessibility_back" systemui:keyCode="4" systemui:glowBackground="@drawable/ic_sysbar_highlight" />
                <View android:visibility="invisible" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1.0" />
                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@id/home" android:layout_width="80.0dip" android:layout_height="fill_parent" android:src="@drawable/ic_sysbar_home" android:layout_weight="0.0" android:contentDescription="@string/accessibility_home" systemui:keyCode="3" systemui:keyRepeat="false" systemui:glowBackground="@drawable/ic_sysbar_highlight" />
                <View android:visibility="invisible" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1.0" />
                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@id/recent_apps" android:layout_width="80.0dip" android:layout_height="fill_parent" android:src="@drawable/ic_sysbar_recent" android:layout_weight="0.0" android:contentDescription="@string/accessibility_recent" systemui:glowBackground="@drawable/ic_sysbar_highlight" />
                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@id/menu" android:visibility="invisible" android:layout_width="40.0dip" android:layout_height="fill_parent" android:src="@drawable/ic_sysbar_menu" android:layout_weight="0.0" android:contentDescription="@string/accessibility_menu" systemui:keyCode="82" systemui:glowBackground="@drawable/ic_sysbar_highlight" />
            </LinearLayout>
            <LinearLayout android:orientation="horizontal" android:id="@id/lights_out" android:visibility="gone" android:layout_width="fill_parent" android:layout_height="fill_parent">
                <ImageView android:layout_width="80.0dip" android:layout_height="fill_parent" android:layout_marginLeft="40.0dip" android:src="@drawable/ic_sysbar_lights_out_dot_small" android:scaleType="center" android:layout_weight="0.0" />
                <View android:visibility="invisible" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1.0" />
                <ImageView android:layout_width="80.0dip" android:layout_height="fill_parent" android:src="@drawable/ic_sysbar_lights_out_dot_large" android:scaleType="center" android:layout_weight="0.0" />
                <View android:visibility="invisible" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1.0" />
                <ImageView android:layout_width="80.0dip" android:layout_height="fill_parent" android:layout_marginRight="40.0dip" android:src="@drawable/ic_sysbar_lights_out_dot_small" android:scaleType="center" android:layout_weight="0.0" />
            </LinearLayout>
            <View android:layout_gravity="top" android:id="@id/deadzone" android:clickable="true" android:layout_width="fill_parent" android:layout_height="@dimen/navigation_bar_deadzone_size" />
        </FrameLayout>
        <FrameLayout android:id="@id/rot90" android:paddingTop="0.0dip" android:visibility="gone" android:layout_width="fill_parent" android:layout_height="fill_parent">
            [COLOR="Green"]<LinearLayout android:orientation="vertical" [COLOR="Red"]android:id="@id/nav_buttons"[/COLOR] android:clipChildren="false" android:clipToPadding="false" android:layout_width="fill_parent" android:layout_height="fill_parent" android:animateLayoutChanges="true">[/COLOR]
                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@id/menu" android:visibility="invisible" android:layout_width="fill_parent" android:layout_height="40.0dip" android:src="@drawable/ic_sysbar_menu_land" android:layout_weight="0.0" android:contentDescription="@string/accessibility_menu" systemui:keyCode="82" systemui:glowBackground="@drawable/ic_sysbar_highlight_land" />
                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@id/recent_apps" android:layout_width="fill_parent" android:layout_height="80.0dip" android:src="@drawable/ic_sysbar_recent_land" android:layout_weight="0.0" android:contentDescription="@string/accessibility_recent" systemui:glowBackground="@drawable/ic_sysbar_highlight_land" />
                <View android:visibility="invisible" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1.0" />
                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@id/home" android:layout_width="fill_parent" android:layout_height="80.0dip" android:src="@drawable/ic_sysbar_home_land" android:layout_weight="0.0" android:contentDescription="@string/accessibility_home" systemui:keyCode="3" systemui:keyRepeat="false" systemui:glowBackground="@drawable/ic_sysbar_highlight_land" />
                <View android:visibility="invisible" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1.0" />
                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@id/back" android:layout_width="fill_parent" android:layout_height="80.0dip" android:src="@drawable/ic_sysbar_back_land" android:layout_weight="0.0" android:contentDescription="@string/accessibility_back" systemui:keyCode="4" systemui:glowBackground="@drawable/ic_sysbar_highlight_land" />
                <View android:visibility="invisible" android:layout_width="fill_parent" android:layout_height="40.0dip" android:layout_weight="0.0" />
            </LinearLayout>
            <LinearLayout android:orientation="vertical" android:id="@id/lights_out" android:visibility="gone" android:layout_width="fill_parent" android:layout_height="fill_parent">
                <ImageView android:layout_width="fill_parent" android:layout_height="80.0dip" android:layout_marginTop="40.0dip" android:src="@drawable/ic_sysbar_lights_out_dot_small" android:scaleType="center" android:layout_weight="0.0" />
                <View android:visibility="invisible" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1.0" />
                <ImageView android:layout_width="fill_parent" android:layout_height="80.0dip" android:src="@drawable/ic_sysbar_lights_out_dot_large" android:scaleType="center" android:layout_weight="0.0" />
                <View android:visibility="invisible" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1.0" />
                <ImageView android:layout_width="fill_parent" android:layout_height="80.0dip" android:layout_marginBottom="40.0dip" android:src="@drawable/ic_sysbar_lights_out_dot_small" android:scaleType="center" android:layout_weight="0.0" />
            </LinearLayout>
            <View android:layout_gravity="left" android:id="@id/deadzone" android:clickable="true" android:layout_width="@dimen/navigation_bar_deadzone_size" android:layout_height="fill_parent" />
        </FrameLayout>
        <View android:id="@id/rot270" android:visibility="gone" android:layout_width="fill_parent" android:layout_height="fill_parent" />
    </com.android.systemui.statusbar.phone.NavigationBarView>


    Now we can call methods we could normally call on a View object. Add
    Code:
    navbar.setBackgroundColor(Color.BLUE);

    When you run this on your phone, your navigation bar will be blue. Now of course you can also call other methods, such as adding in new TextView's or whatever. If you were to inspect the code more closely, you would find there are also ids called "home" "back" and "recent_apps". You could use these to mess around with the buttons, though I cannot imagine what!

    Tutorial 9 - Methods with parameters

    In an earlier tutorial, we covered hooking methods. But what if a method wants a parameter too?

    Say if i want to hook onCreate(Bundle savedInstances) in com.android.settings

    If i hook it using

    Code:
    findAndHookMethod("com.android.settings.Settings", lpparam.classLoader, "onCreate", new XC_MethodHook() {
                
     });

    It will throw a methodNotFound error. So we need to specify the parameters. The method wants a Bundle object. So add Bundle.class as a parameter

    Code:
    findAndHookMethod("com.android.settings.Settings", lpparam.classLoader, "onCreate", [B]Bundle.class[/B], new XC_MethodHook() {
                
     });

    Now lets pretend Bundle.class isnt in the SDK and is a system class so cant be referenced. I would use a String instead:

    "android.os.Bundle"

    Code:
    findAndHookMethod("com.android.settings.Settings", lpparam.classLoader, "onCreate", [B]"android.os.Bundle"[/B], new XC_MethodHook() {
                
     });
    5
    The next few tutorials are up,
    1-Setting Up
    2-Background Info on Xposed
    3-Exploring Your Target
    4-The Code
    3
    The full tutorial is now at the top of this thread and all future tutorials will be added to that post. I will also post another post on this thread when i add one so subscribers will get a message
    2
    Great guide! And Congratulations! You are on XDA Portal!

    I was compiling this guide in MS Word, but you did it first!

    Congrats again!
    2
    Nice Tutorials, but this what you've posted until now is already published by a lot of peoples (also on the offical GitHub-Page).
    It would be awesome if you show some other (non-public) Tutorials, e.g how to make a PreferenceMenu and use it ;)

    #KeepItUp

    In this tutorial i plan to explain every feature of Xposed thoroughly