QML: Get Android battery level and status


This post will explain a way to get Android battery level and status from QML. To be more precise will explain the way to install a sort of listener that will automatically advise the QML layer about changes in level of battery charge and the status of the phone (if on charge or not).



Full project example can be found here

Official Android documentation  propose a solution here. This solution cover the special case to be advised about battery low level or charging status also if your app is not running at that time. Also the code to get battery level have to be called directly by the app. Solution proposed here is different since require the listener code to be installed manually and it will work only if your app is currently running. As obvious this solution will require to use some java code to interface with Android API as follow:

public class BatteryLevelListener
{
    private static Activity m_ActivityInstance;

    public static void Init(Activity ActivityInstance)
    {
        m_ActivityInstance = ActivityInstance;
    }

    public static native void BatteryStateChanged(int Level, boolean OnCharge);

    public static void InstallBatteryListener()
    {
        IntentFilter BatteryLevelFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);

        BroadcastReceiver BatteryLevelReceiver = new BroadcastReceiver()
        {
            public void onReceive(Context context, Intent intent)
            {
                boolean OnCharge = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) == 0) ? false : true;
                int Level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
                int Scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);

                if(Level >= 0 && Scale > 0)
                {
                    BatteryStateChanged((Level * 100) / Scale, OnCharge);
                }
            }
        };

        m_ActivityInstance.registerReceiver(BatteryLevelReceiver, BatteryLevelFilter);
    }
}

Main C++ Qt code will call the InstallBatteryListener() method for "connect" a function to the ACTION_BATTERY_CHANGED event. This special event will be called every time the battery change in level or change the charging status. This event is also classified as sticky, that's mean the event will be called immediately after installation with the last battery status registered. This will be very useful to be immediately updated regarding the current/last battery info. Main C++ code is quite simple as follow:

QObject *pQmlRootObject = NULL;

void AndroidBatteryStateChanged(JNIEnv *env, jobject thiz, jint level, jboolean onCharge)
{
    Q_UNUSED(env)
    Q_UNUSED(thiz)

    if(pQmlRootObject != NULL)
    {
        QMetaObject::invokeMethod(pQmlRootObject,
                                  "androidBatteryStateChanged",
                                  Qt::AutoConnection,
                                  Q_ARG(QVariant, level),
                                  Q_ARG(QVariant, onCharge)
                                  );
    }
}

void InitializeForAndroid()
{
    JNINativeMethod methods[] = {
        {
            "BatteryStateChanged",
            "(IZ)V",
            reinterpret_cast(AndroidBatteryStateChanged)
        }
    };

    QAndroidJniObject javaClass("com/falsinsoft/example/batterylevel/BatteryLevelListener");
    QAndroidJniEnvironment env;

    jclass objectClass = env->GetObjectClass(javaClass.object());

    env->RegisterNatives(objectClass,
        methods,
        sizeof(methods) / sizeof(methods[0]));
    env->DeleteLocalRef(objectClass);

    QAndroidJniObject::callStaticMethod("com/falsinsoft/example/batterylevel/BatteryLevelListener", "InstallBatteryListener");
}

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));

    pQmlRootObject = engine.rootObjects().at(0);
    InitializeForAndroid();

    return app.exec();
}

The code will register the function called from java and will install the listener through the installer function. Please note this example will return only the basic info regarding battery. Using additional Android params it will be possible to get additional info like, for example, if the device is charging through USB or power adapter and so on. Result is the following app, very simple showing the data captured on real time.


Comments

Popular posts from this blog

Access GPIO from Linux user space

Launch an app from Android shell terminal