👋 Hello there!
This article is mainly for users who know about ROOTED android and already have one. If you are not one of them, you can still read this article, but I will not recommend that.
First of all, I would like to give a brief introduction to what is the Xposed Framework is.
Xposed is a framework that allows users to easily apply add-ons (called Modules) to the ROM. Rather than flashing a new ROM to get a specific feature, you can use Xposed to add individual features to whatever ROM you’re using, or even just the stock ROM.
[source]
Xposed was created by the developers from the XDA community. I will not dig into too much into the history of the Xposed Framework. Here I am assuming you already know (or having) below things:
- A ROOTED Android device (yes.. it must be rooted)
— [DISCLAIMER: Rooting will void the device’s WARRENTY] —
— “IF YOU ARE NOT SURE WHAT YOU’RE DOING, DON’T DO IT!” —
[It would take whole another article if you ask how to root. You can simply google it because methods for rooting is a device-dependent, just google for your ones. Also, you will need to unlock your bootloader.] - Working Xposed Framework installation
[Refer this link if you are already having a rooted device and want to install the Xposed Framework] - Some basic Android development skills and familiar with Android Studio (preferred) or Eclipse. I will continue further steps in Android Studio.
Here is also a good article about the Working with Xposed Framework by Emilie H Wilson.
What are we gonna create?
We’ll create an Xposed module that will change the color of your device’s clock on the status bar. Sounds cool!! isn’t it??
Have a look at below image of my device’s status bar which is having a red clock.
Without further ado, let’s get started..!
STEP — 1: Open Android Studio
If you don’t have it, you can download it from here: link.
STEP — 2: Activity Selection
Create a new Android Studio Project. (See image below)
I am keeping this tutorial simple, we do not need to create any activity as we are just changing the color of the status bar’s clock.
Select No Activity and go to Next.
STEP — 3: Project Configuration
Specify the name and package name for your application. Keep the language as Java, if you are familiar with Kotlin, go with that — there will be not that much hard coding as this is kind of a ‘hello-world’ app/module development.
I am keeping the minimum API level to 15.
Then hit the Finish button.
STEP — 4: Modify your build.gradle (app) & Add below dependencies:
...repositories {
jcenter()
}
dependencies {
...
// Xposed Framework API dependencies
provided 'de.robv.android.xposed:api:82'
provided 'de.robv.android.xposed:api:82:sources'
}
Then, sync the project.
STEP — 5: Modify your manifest.xml file:
Add below meta-data tags inside of application tag:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<meta-data
android:name="xposedmodule"
android:value="true" />
<meta-data
android:name="xposeddescription"
android:value="An example which changes the color of clock text in status bar" />
<meta-data
android:name="xposedminversion"
android:value="53" />
</application>
The name should be xposedmodule
and the value true
. Leave the resource empty. Then repeat the same for xposedminversion
(the API version from the previous step) and xposeddescription
(a very short description of your module).
STEP — 6: Create a class:
package com.myfirstxposedmodule;
public class MyModule {
}
This is our class that we will modify in the future.
STEP — 7: Create and modify xposed_init file
:
Change the directory view to the Project view. Navigate to app > src > main. Right-click on main and select new > directory.
Name it: assets
Right-click on the recently created assets
directory, select new > file.
Name it: xposed_init
(select text
if it asks for file-type).
Inside xposed_init
file, add full name of our java class. i.e. in our case, it will be like:
com.myfirstxposedmodule.MyModule
This is how the Xposed framework will identify our module and will load it on the boot. This file will tell the framework which classes to load, which also we’ll see in the logs.
STEP — 8: Modify MyModule class:
package com.myfirstxposedmodule;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import de.robv.android.xposed.XposedBridge;
public class MyModule implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
}
}
Implement IXposedHookLoadPackage
and implement the method handleLoadPackage
as shown above.
Now, let’s try out by putting a log function inside that handleLoadPackage
method:
XposedBridge.log("Loaded app: " + lpparam.packageName);
This will print the loaded modules. Generally, these logs are logged inside this file: /data/data/de.robv.android.exposed.installer/log/debug.log
(which is easily accessible via the Xposed Installer).
STEP — 9: Run the code:
If you directly try to run this from the android studio, you’ll get this error. Which is ok because we are not having any activity right now.
Anyway, don’t worry, I am having a solution. Just edit the Run configuration and change Launch Option from Default Activity to Nothing and select Ok.
Now, again try to run (Windows: Shift + F10).
On successful run on your device, you’ll be able to see this module in the Xposed Installer app’s module’s list. As shown in the below image, also you can see the description text which we had entered in the manifest file.
Just, activate that module by checking the box and reboot your device. After reboot, open the Xposed Installer application and open the logs (you can also open the log file which I mentioned above its the path). You will see lines like this:
EdXposed-Bridge: Loading modules from /data/app/com.myfirstxposedmodule-en1q0c1NI6hi_M02fRwp-g==/base.apk
EdXposed-Bridge: Loading class com.myfirstxposedmodule.MyModule
EdXposed-Bridge: Loaded app: android
EdXposed-Bridge: Loaded app: org.lineageos.lineagesettings
EdXposed-Bridge: Loaded app: com.android.providers.settings
EdXposed-Bridge: Loaded app: com.android.systemui
Now that you know how to create and run the Xposed module, we can go further deep down to look at the status bar’s code and apply some of our own implementations.
STEP — 10: Digging into the status bar’s code:
Now, we are interested in getting the clock (text) from the status bar (which is residing into com.android.systemui
package). As you know the Android is an open-source operating source, so that you can see the inside stuff of the code. You can download the source code of android from THIS link. Depending on your android version and your rom, there might be some changes. As of now, we are only interested in finding our clock’s code. There is a Clock.java
class inside somewhere in com.android.systemui
package and this class extends TextView
which means that you can treat this similar like a TextView. THIS is the link to that class. There is one method which updates the time on the status bar whose name is updateClock()
. Look at below snippet:
...final void updateClock() {
if (mDemoMode) return;
mCalendar.setTimeInMillis(System.currentTimeMillis());
setText(getSmallTime());
setContentDescription(mContentDescriptionFormat.format(mCalendar.getTime()));
}...
Now, what we want? We want to run our code whenever this method gets executed. Which we’ll do in the next step, which is also known as hooking a method.
STEP — 11: Hooking the method:
The XposedHelper
is a class that provides some helper methods. One helper method which we will need is findAndHookMethod
which takes the full class name in String
, class loader (we can get it from XC_LoadPackage.LoadPackageParam
from handleLoadPackage
), the method name which we want to track ( updateClock
in our case)in String
and XC_MethodHook
call-back (which is simply a callback). Below will be our code
XposedHelpers.findAndHookMethod("com.android.systemui.statusbar.policy.Clock", lpparam.classLoader, "updateClock", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
}
});
In the above code, you can see that there are two methods which I have implemented in the anonymous class XC_MethodHook
which are beforeHookedMethod
and afterHookedMethod
. As the name suggests first one will be get executed before the hooked method and the latter one will be executed after the hooked method (updateClock
in our case). The parameters for arguments and return-types are handled by MethodHookParam
argument. But as of now, we just want to change the status bar’s clock’s color, we will simply need afterHookedMethod
.
We will need access to that TextView
object, which we can get from param.thisObject
— this’ll be the same as this
keyword in Clock.java
class. Then we can cast it to TextView
and then we can simply change the color of that TextView
object and also can modify the text as I did:
XposedHelpers.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;
String text = tv.getText().toString();
tv.setText(text + " :)");
tv.setTextColor(Color.RED);
}
});
STEP — 12: Run the Module:
Run the code and again reboot your device. You will be able to see your clock in red and that emoji text we appended.
That’s it!! I know that rebooting sucks! but hey, you have created your own Xposed module, isn’t that great??!!
I had gone through these great resources:
1. GitHub — Development tutorial by rovo89 and
2. XDA — [TUTORIAL] Xposed module development
If you are having any questions, feel free to ask in comments. And if you like my first article, feel free to clap 👏 and share with your favorite developer friends.