Evgenii Legotckoi
Evgenii LegotckoiJune 30, 2016, 12:53 p.m.

QML - Lesson 026. Intents with Qt for Android, part 1

The “ intent ” is the main facility for interprocess communication on Android. Basically, an intent is an object that is processed by the operating system and then passed to one or more of the installed applications based on its contents. It could for instance be a request to show a video, in which case the intent type would be ACTION_VIEW and the mime type would be set accordingly. Applications can subscribe to certain intents by setting an intent filter in their manifest files. The first time a type of intent is seen, the user of the device will be presented with a selection of applications known to subscribe to that type of intent. If they choose, they can set a default at this point, or select to be asked for every instance.

This is the first of a few articles showing how to use intents with Qt for Android.

The mechanism itself is quite general. What is described above is one use case, but intents are also used for other things: One such thing is launching services inside the application. This is usually formatted as an “explicit intent”, meaning that the fully qualified name of the service to start is provided, so it cannot be intercepted by any other applications.

Another way intents are used is for broadcasts, for instance when the time zone of the device changes. While the action to view a video described above would only launch the one specific application selected by the user, a broadcast will rather be passed to any application which subscribes to it.


This blog will focus on Android, but a similar mechanism called app extensions was introduced in iOS 8.

In this first article about intents on Android, I will focus on the simplest use case: Creating an implicit intent from Qt to start an unspecified application on the target device. As an example, I have made a simple application which presents food recipes. Each recipe has an estimated time for completion. By clicking a button, you can set a timer using the preferred countdown application on the device. (For a more useful use case, one might imagine a button setting a timer for each of the steps in the recipe’s directions, but for this simple example we will only have a single timer per recipe.)

I won’t go into detail about how the application itself is written, but the code can be found here . No effort has been made to make the UI look nice, so please disregard that. The application is backed by an SQLite database (which is filled with some dummy content the first time the application is started) and has a very simple UI written in Qt Quick Controls 2, allowing the user to select a recipe from a list, see its details on a separate page and click a button on the recipe to set a timer in the system.

The part we will focus on is the code that actually requests the timer from the system. This is in the

recipe.cpp
file, in the function
Recipe::createTimer()
. For our example we will be using the AlarmClock.ACTION_SET_TIMER intent type.

We will use the JNI convenience APIs in the Qt Android Extras module for this. I will go through this code step by step.

QAndroidJniObject ACTION_SET_TIMER = QAndroidJniObject::getStaticObjectField("android/provider/AlarmClock",
                                                                                      "ACTION_SET_TIMER");
QAndroidJniObject intent("android/content/Intent",
                         "(Ljava/lang/String;)V",
                         ACTION_SET_TIMER.object());

Since we are only using functions from Qt Android Extras and no explicit calls using the JNI APIs, we don’t have to worry about reference management. This is one primary convenience of the APIs.The first step is to create the intent. We retrieve the identifier of the ACTION_SET_TIMER intent. This is a static member of the android.provider.AlarmClock class and is of type String. Note the use of slashes in place of dots in the package name of the class. This corresponds to the bytecode representation of package names (for historical reasons according to the specification ) and is therefore also used in signatures in JNI.

The next step is to actually create the intent object. We do this by constructing a QAndroidJniObject, passing in the JNI-mangled signature of the Java constructor we want to call and we pass in the ID of the action we just got from the AlarmClock class.

QAndroidJniObject EXTRA_MESSAGE = QAndroidJniObject::getStaticObjectField("android/provider/AlarmClock",
                                                                                   "EXTRA_MESSAGE");
QAndroidJniObject messageObject = QAndroidJniObject::fromString(message);
intent.callObjectMethod("putExtra",
                        "(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;",
                        EXTRA_MESSAGE.object(),
                        messageObject.object());

QAndroidJniObject EXTRA_LENGTH = QAndroidJniObject::getStaticObjectField("android/provider/AlarmClock",
                                                                                  "EXTRA_LENGTH");
intent.callObjectMethod("putExtra",
                        "(Ljava/lang/String;I)Landroid/content/Intent;",
                        EXTRA_LENGTH.object(),
                        jint(m_time * 60));

QAndroidJniObject EXTRA_SKIP_UI = QAndroidJniObject::getStaticObjectField("android/provider/AlarmClock",
                                                                                  "EXTRA_SKIP_UI");
intent.callObjectMethod("putExtra",
                        "(Ljava/lang/String;Z)Landroid/content/Intent;",
                        EXTRA_SKIP_UI.object(),
                        jboolean(true));

Next up, we set up some arguments we want to send to the activity handling the action. We pass in a description of the timer and the number of seconds to set it for.

QAndroidJniObject activity = QtAndroid::androidActivity();
QAndroidJniObject packageManager = activity.callObjectMethod("getPackageManager",
                                                             "()Landroid/content/pm/PackageManager;");
QAndroidJniObject componentName = intent.callObjectMethod("resolveActivity",
                                                          "(Landroid/content/pm/PackageManager;)Landroid/content/ComponentName;",
                                                          packageManager.object());

Then we have to resolve the activity. This will tell the system to check if there is an application available to handle the ACTION_SET_TIMER action. We first get a reference to the current activity (our current context ) in order to get the appropriate package manager . Then we call resolveActivity() on the intent and pass in the package manager.

if (componentName.isValid()) {
    QtAndroid::startActivity(intent, 0);
} else {
    qWarning() << "Unable to resolve activity";
}

If the returned component name is non-null, we start the activity using the convenience function in Qt Android Extras. We will look at more features of this function in a later blog. If no appropriate activity is found, then this code only outputs a warning to the console. A proper application might complain in the actual user interface, but note that the operating system has also alerted the user of the problem at this point.

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

S
  • Oct. 4, 2020, 5:48 p.m.
  • (edited)

Есть ли возможность приведения java типа у QAndroidJniObject? Интересует конкретно class to

Comments

Only authorized users can post comments.
Please, Log in or Sign up
AD

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:50points,
  • Rating points-4
m

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:80points,
  • Rating points4
m

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:20points,
  • Rating points-10
Last comments
ИМ
Игорь МаксимовNov. 22, 2024, 11:51 a.m.
Django - Tutorial 017. Customize the login page to Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii LegotckoiOct. 31, 2024, 2:37 p.m.
Django - Lesson 064. How to write a Python Markdown extension Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZEOct. 19, 2024, 8:19 a.m.
Fb3 file reader on Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь МаксимовOct. 5, 2024, 7:51 a.m.
Django - Lesson 064. How to write a Python Markdown extension Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas5July 5, 2024, 11:02 a.m.
QML - Lesson 016. SQLite database and the working with it in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Now discuss on the forum
Evgenii Legotckoi
Evgenii LegotckoiJune 24, 2024, 3:11 p.m.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey1Nov. 15, 2024, 6:04 a.m.
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProjectJune 4, 2022, 3:49 a.m.
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9AnonimOct. 25, 2024, 9:10 a.m.
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

Follow us in social networks