📜 ⬆️ ⬇️

Using D-Bus system functions in Sailfish OS

Introduction


This article is a continuation of the material on the use of the system API in Sailfish OS and is devoted to the functions of the D-Bus in this operating system. The interaction with the standard calendar and flash will be analyzed in detail. A list of the remaining main functions of the D-Bus system is provided at the end of the article.

To understand the material, it is necessary to know the basics of development for Sailfish OS and the principles of interaction with the D-Bus within the operating system. A good starting point is the relevant FRUCT articles:

[1] Begin development for Sailfish OS ;
[2] Development for Sailfish OS: work with D-Bus .

Theory


There are two ways to obtain information about the available interfaces and functions of the D-Bus. The first approach is to study the interfaces registered in the system using special utilities (for example, Visual D-Bus and D-Bus Inspector ) or the command line (Figure 1). The second approach uses the source code study methodology described in the previous article.
')

[Figure 1 - An example of getting a list of D-Bus interfaces.]

The great advantage of the first approach is the possibility of obtaining information about the interfaces “wired” into binary files and inaccessible in text form, but this way you can analyze only the currently active interfaces. The second approach used in the framework of this article inverts the described plus and minus of the first approach.

Equipment


D-Bus functions can be called (or defined) from C ++ code (which is not available on the system), from QML code, and from desktop application files. Accordingly, when searching for information about the interfaces, you must have an idea, firstly, about the org.nemomobile.dbus module; secondly, about the way to access the D-Bus from the desktop-files.

The org.nemomobile.dbus QML module provides two main components for working with D-Bus: DBusAdaptor and DBusInterface . The first allows the application to create its own interface, the second - to use the existing one. In general information retrieval, both components are of interest, as they allow you to learn how to interact with the application from the outside, and how the application uses third-party interfaces, respectively.

For example, to find out which D-Bus interfaces the settings application uses, you need to go to the /usr/share/jolla-settings and check for D-Bus usage:

grep -i -H 'dbus' * && grep -A 5 'DBusAdaptor' ./settings.qml
 $ cd /usr/share/jolla-settings/ $ grep -i -H 'dbus' * settings.qml:import org.nemomobile.dbus 2.0 settings.qml: DBusAdaptor { $ grep -A 5 'DBusAdaptor' ./settings.qml DBusAdaptor { service: "com.jolla.settings" path: "/com/jolla/settings/ui" iface: "com.jolla.settings.ui" function showSettings() { 


At the same time, when analyzing desktop files, it must be remembered that, firstly, desktop files are stored in the /usr/share/applications directory; secondly, using the described functions starts an instance of the application; thirdly, when describing interaction with D-Bus, fields with the X-Maemo prefix are used:


Interesting to know
X-Maemo prefixes appeared in Sailfish OS as a legacy from the Maemo operating system (Figure 2), previously developed by Nokia. They allow you to declare D-Bus functions in such a way that they can be accessed without first running the program. These functions allow you to start the program with the implementation before it opens some preliminary work.

image
[Figure 2 - The dependence of Sailfish OS on other operating systems ( Wikipedia ).]

It is worth noting that in desktop files it is possible to use the MimeType field to specify the types of files that the program can handle. An example implementation is available on GitHub .

Thus, to get a list of all applications that support launch using D-Bus, you need to go to the /usr/share/applications directory and search for one of the keywords:

grep -H 'X-Maemo-Service' *
 $ cd /usr/share/applications/ $ grep -H 'X-Maemo-Service' * jolla-calendar-import.desktop:X-Maemo-Service=com.jolla.calendar.ui jolla-calendar.desktop:X-Maemo-Service=com.jolla.calendar.ui jolla-camera-viewfinder.desktop:X-Maemo-Service=com.jolla.camera jolla-clock.desktop:X-Maemo-Service=com.jolla.clock jolla-contacts-import.desktop:X-Maemo-Service=com.jolla.contacts.ui jolla-email.desktop:X-Maemo-Service=com.jolla.email.ui jolla-gallery-openfile.desktop:X-Maemo-Service=com.jolla.gallery jolla-gallery-playvideostream.desktop:X-Maemo-Service=com.jolla.gallery jolla-mediaplayer-openfile.desktop:X-Maemo-Service=com.jolla.mediaplayer jolla-mediaplayer.desktop:X-Maemo-Service=com.jolla.mediaplayer jolla-messages-openurl.desktop:X-Maemo-Service=org.nemomobile.qmlmessages jolla-messages.desktop:X-Maemo-Service=org.nemomobile.qmlmessages jolla-notes-import.desktop:X-Maemo-Service=com.jolla.notes jolla-notes.desktop:X-Maemo-Service=com.jolla.notes jolla-settings.desktop:X-Maemo-Service=com.jolla.settings new-mail.desktop:X-Maemo-Service=com.jolla.email.ui open-url.desktop:X-Maemo-Service=org.sailfishos.browser.ui ovpn-import.desktop:X-Maemo-Service=com.jolla.settings sailfish-office-openfile.desktop:X-Maemo-Service=org.sailfish.office sailfish-office.desktop:X-Maemo-Service=org.sailfish.office simkit.desktop:X-Maemo-Service=org.sailfish.simkit voicecall-ui-openurl.desktop:X-Maemo-Service=com.jolla.voicecall.ui voicecall-ui.desktop:X-Maemo-Service=com.jolla.voicecall.ui 


A summary table of the main system functions API and D-Bus is given at the end of the article.

Practice


The theoretical material presented in the current and previous articles allows you to implement your components to work with the system functions of the D-Bus.

Create a component that allows you to open the schedule for the current day. To do this, go to the /usr/share/jolla-calendar directory (principles of directory naming were described in the previous article) and find out which files have a D-Bus address:

grep -r -i -H 'dbus' *
 $ cd /usr/share/jolla-calendar/ $ grep -r -i -H 'dbus' * DbusInvoker.qml:import org.nemomobile.dbus 2.0 DbusInvoker.qml:DBusAdaptor { calendar.qml:import org.nemomobile.dbus 2.0 calendar.qml: DbusInvoker {} 


From the result of the command, it is clear that the interface definitions are made in the DbusInvoker.qml file, which contains only the definitions of the interface and D-Bus functions:

cat ./DbusInvoker.qml -n
 $ cat ./DbusInvoker.qml -n 1 import QtQuick 2.0 2 import Sailfish.Silica 1.0 3 import org.nemomobile.dbus 2.0 4 import Calendar.dateParser 1.0 5 6 DBusAdaptor { 7 service: "com.jolla.calendar.ui" 8 path: "/com/jolla/calendar/ui" 9 iface: "com.jolla.calendar.ui" 10 11 function viewEvent(id, recurrenceId, startDate) { 12 var occurrence = DateParser.parseTime(startDate) 13 if (isNaN(occurrence.getTime())) { 14 console.warn("Invalid event start date, unable to show event") 15 return 16 } 17 18 if (pageStack.currentPage.objectName === "EventViewPage") { 19 pageStack.currentPage.uniqueId = id 20 pageStack.currentPage.recurrenceId = recurrenceId 21 pageStack.currentPage.startTime = occurrence 22 } else { 23 pageStack.push("pages/EventViewPage.qml", 24 { uniqueId: id, recurrenceId: recurrenceId, startTime: occurrence }, 25 PageStackAction.Immediate) 26 } 27 requestActive.start() 28 } 29 30 function viewDate(dateTime) { 31 var parsedDate = new Date(dateTime) 32 if (isNaN(parsedDate.getTime())) { 33 console.warn("Invalid date, unable to show events for date") 34 return 35 } 36 37 if (pageStack.currentPage.objectName === "DayPage") { 38 pageStack.currentPage.date = parsedDate 39 } else { 40 pageStack.push("pages/DayPage.qml", { date: parsedDate }, PageStackAction.Immediate) 41 } 42 requestActive.start() 43 } 44 45 function importFile(fileName) { 46 if (pageStack.currentPage.objectName === "ImportPage") { 47 pageStack.currentPage.fileName = fileName 48 } else { 49 pageStack.push("pages/ImportPage.qml", { "fileName": fileName }, PageStackAction.Immediate) 50 } 51 requestActive.start() 52 } 53 54 function activateWindow(arg) { 55 app.activate() 56 } 57 } 


From the adapter code, you can see that in the component being created you need to connect to the com.jolla.calendar.ui service and use the path /com/jolla/calendar/ui and the interface com.jolla.calendar.ui (lines 7-9). After that, the declared functions will become available, of which, within the framework of the task, only the viewDate (lines 30-43) is of interest, taking as argument one of the date representations recognized by the Date object. The results obtained allow you to implement your component to work with the calendar:

CalendarController.qml
 import QtQuick 2.0 import Sailfish.Silica 1.0 import org.nemomobile.dbus 2.0 Item { id: calendarControl /*     . */ function showAgenda() { calendar.call('viewDate', Date.now()) } DBusInterface { id: calendar service: 'com.jolla.calendar.ui' path: '/com/jolla/calendar/ui' iface: 'com.jolla.calendar.ui' } } 


By the same principle, other components are also formed that interact with the functions of the D-Bus system.

Consider the flash control process. To do this, according to the analysis of the /usr/share/jolla-settings/pages/flashlight directory, you must connect to the com.jolla.settings.system.flashlight service and use the path /com/jolla/settings/system/flashlight and the interface com.jolla.settings.system.flashlight . After that, by calling the toggleFlashlight function without parameters, it becomes possible to turn the flash on and off.

However, in some tasks it may be necessary to obtain information about the current state of the flash - whether it is on or off. To do this, use the getProperty function with the "flashlightOn" parameter passed to it. In this case, returns a boolean value.

grep -i -H 'dbus' ./pages/flashlight/* && grep -A 5 -i -H 'DBusInterface' ./pages/flashlight/Flashlight.qml
 $ cd /usr/share/jolla-settings $ grep -i -H "dbus" ./pages/flashlight/* ./pages/flashlight/Flashlight.qml:import org.nemomobile.dbus 2.0 ./pages/flashlight/Flashlight.qml: flashlightDbus.call("toggleFlashlight", undefined, handleToggle, handleError) ./pages/flashlight/Flashlight.qml: property QtObject flashlightDbus: DBusInterface { ./pages/flashlight/Flashlight.qml: flashlight.flashlightOn = flashlightDbus.getProperty("flashlightOn") $ grep -A 5 -i -H "DBusInterface" ./pages/flashlight/Flashlight.qml ./pages/flashlight/Flashlight.qml: property QtObject flashlightDbus: DBusInterface { ./pages/flashlight/Flashlight.qml- signalsEnabled: true ./pages/flashlight/Flashlight.qml- service: "com.jolla.settings.system.flashlight" ./pages/flashlight/Flashlight.qml- path: "/com/jolla/settings/system/flashlight" ./pages/flashlight/Flashlight.qml- iface: "com.jolla.settings.system.flashlight" ./pages/flashlight/Flashlight.qml- function flashlightOnChanged(newOn) { 


Considering the above, the component for interacting with the flash is implemented:

FlashlightController.qml
 import QtQuick 2.0 import Sailfish.Silica 1.0 import org.nemomobile.dbus 2.0 Item { id: flashlightControl //  . property bool flashlightOn //    . function toggleFlashlight() { flashlightOn = !flashlightOn; flashlight.call("toggleFlashlight", undefined); } DBusInterface { id: flashlight service: "com.jolla.settings.system.flashlight" path: "/com/jolla/settings/system/flashlight" iface: "com.jolla.settings.system.flashlight" signalsEnabled: true function flashlightOnChanged(newOn) { flashlightControl.flashlightOn = newOn } } Component.onCompleted: { flashlightControl.flashlightOn = flashlight.getProperty("flashlightOn") } } 


Conclusion


This article describes two ways to search for information about the functions of D-Bus in Sailfish OS, and one of them is analyzed in detail - search in the source code. With its use, examples of components for interacting with the flash and the standard calendar have been developed and commented. The code for these and other modules is available on GitHub .

However, one should not forget that the solution of a part of the problems is possible by simply launching the program of interest with the required arguments. For example, the launch of a standard browser with the opening of the site can be carried out using the sailfish-browser https://google.com/ command sailfish-browser https://google.com/ . But this is beyond the scope of the material described in the article.

sailfish-browser https://google.com/
 $ sailfish-browser https://google.com/ [D] unknown:0 - Using Wayland-EGL greHome from GRE_HOME:/usr/bin libxul.so is not found, in /usr/bin/libxul.so Created LOG for EmbedLite [D] onCompleted:103 - ViewPlaceholder requires a SilicaFlickable parent Loaded xulDir:/usr/lib/xulrunner-qt5-38.8.0/libxul.so, appDir:/usr/bin EmbedLiteExt virtual nsresult EmbedChromeManager::Observe(nsISupports*, const char*, const char16_t*):82: obj:(nil), top:app-startup EmbedLiteExt virtual nsresult EmbedTouchManager::Observe(nsISupports*, const char*, const char16_t*):86: obj:(nil), top:app-startup EmbedLiteGlobalHelper app-startup EmbedLiteSyncService app-startup PREFS SERVICE INITAILIZED EmbedPrefService app-startup EmbedliteDownloadManager initialized UserAgentOverrideHelper app-startup 1505073762747 addons.manager DEBUG Application has been upgraded 1505073762892 addons.manager DEBUG Loaded provider scope for resource://gre/modules/addons/XPIProvider.jsm: ["XPIProvider"] 1505073762912 addons.manager DEBUG Loaded provider scope for resource://gre/modules/LightweightThemeManager.jsm: ["LightweightThemeManager"] 1505073762942 addons.manager DEBUG Loaded provider scope for resource://gre/modules/addons/GMPProvider.jsm 1505073762961 addons.manager DEBUG Loaded provider scope for resource://gre/modules/addons/PluginProvider.jsm 1505073762968 addons.manager DEBUG Starting provider: XPIProvider 1505073762973 addons.xpi DEBUG startup 1505073762982 addons.xpi DEBUG checkForChanges 1505073762993 addons.xpi DEBUG Loaded add-on state from prefs: {} 1505073763000 addons.xpi DEBUG getInstallState changed: false, state: {} 1505073763009 addons.xpi DEBUG Empty XPI database, setting schema version preference to 16 1505073763012 addons.xpi DEBUG No changes found 1505073763015 addons.manager DEBUG Registering shutdown blocker for XPIProvider 1505073763021 addons.manager DEBUG Provider finished startup: XPIProvider 1505073763022 addons.manager DEBUG Starting provider: LightweightThemeManager 1505073763024 addons.manager DEBUG Registering shutdown blocker for LightweightThemeManager 1505073763029 addons.manager DEBUG Provider finished startup: LightweightThemeManager 1505073763032 addons.manager DEBUG Starting provider: GMPProvider 1505073763046 addons.manager DEBUG Registering shutdown blocker for GMPProvider 1505073763050 addons.manager DEBUG Provider finished startup: GMPProvider 1505073763052 addons.manager DEBUG Starting provider: PluginProvider 1505073763055 addons.manager DEBUG Registering shutdown blocker for PluginProvider 1505073763059 addons.manager DEBUG Provider finished startup: PluginProvider 1505073763060 addons.manager DEBUG Completed startup sequence Created LOG for EmbedPrefs [D] QMozWindowPrivate::setSize:71 - Trying to set empty size: QSize(-1, -1) Attempting load of libEGL.so EmbedLiteExt virtual nsresult EmbedTouchManager::Observe(nsISupports*, const char*, const char16_t*):86: obj:0xb225a130, top:domwindowopened EmbedLiteExt void EmbedChromeManager::WindowCreated(nsIDOMWindow*):91: WindowOpened: 0xb225a140 EmbedLiteExt void EmbedTouchManager::WindowCreated(nsIDOMWindow*):95: WindowOpened: 0xb225a140 EmbedLiteExt void EmbedTouchManager::WindowCreated(nsIDOMWindow*):108: id for window: 1 ###################################### SelectAsyncHelper.js loaded ###################################### embedhelper.js loaded ### ContextMenuHandler.js loaded ### SelectionPrototype.js loaded ### SelectionHandler.js loaded Init Called:[object Object] JavaScript warning: https://www.google.ru/xjs/_/js/k=xjs.mhp.en_US.2vKAz7DqmvI.O/m=sb_mobh,hjsa,d,csi/am=AAAD/rt=j/d=1/t=zcms/rs=ACT90oFx8AHVqc9lMfPQBwURKXyQ4qaFiA, line 7: mutating the [[Prototype]] of an object will cause your code to run very slowly; instead create the object with the correct initial [[Prototype]] value using Object.create 


Main system API functions:
DescriptionRequired data
Create atmosphere
 import Sailfish.Ambience 1.0 var previousAmbienceUrl = Ambience.source Ambience.setAmbience(url, function(ambienceId) { pageStack.push(ambienceSettings, { 'contentId': ambienceId, 'previousAmbienceUrl': previousAmbienceUrl }) }) 
Adjust screen brightness
 import org.nemomobile.systemsettings 1.0 DisplaySettings { id: displaySettings } maximumValue: displaySettings.maximumBrightness minimumValue: 1 value: displaySettings.brightness displaySettings.brightness = Math.round(value) 
Adjust screen orientation
 import org.nemomobile.systemsettings 1.0 DisplaySettings { id: displaySettings } displaySettings.orientationLock = "dynamic" //   displaySettings.orientationLock = "portrait" //   displaySettings.orientationLock = "landscape" //   
Automatic adjustment of screen brightness
 import org.nemomobile.systemsettings 1.0 DisplaySettings { id: displaySettings } checked: displaySettings.ambientLightSensorEnabled && displaySettings.autoBrightnessEnabled if (checked) { displaySettings.autoBrightnessEnabled = false } else { displaySettings.autoBrightnessEnabled = true displaySettings.ambientLightSensorEnabled = true } 
Setting the sleep time
 import org.nemomobile.systemsettings 1.0 DisplaySettings { id: displaySettings } displaySettings.dimTimeout = VALUE_IN_SECONDS 
Setting the display status while charging
 import org.nemomobile.systemsettings 1.0 DisplaySettings { id: displaySettings } displaySettings.inhibitMode = DisplaySettings.InhibitOff //      displaySettings.inhibitMode = DisplaySettings.InhibitStayOnWithCharger //       
Setting the system font size
 import org.nemomobile.configuration 1.0 ConfigurationValue { id: fontSizeCategory key: "/desktop/jolla/theme/font/sizeCategory" defaultValue: "normal" } fontSizeCategory.value = "normal" //    fontSizeCategory.value = "large" //    fontSizeCategory.value = "huge" //    
Adjusting the system volume
 import org.nemomobile.systemsettings 1.0 ProfileControl { id: profileControl } maximumValue: 100 minimumValue: 0 profileControl.ringerVolume = value profileControl.profile = (value > 0) ? "general" : "silent" 
Vibration setting
 import org.nemomobile.systemsettings 1.0 ProfileControl { id: soundSettings } soundSettings.vibraMode = ProfileControl.VibraAlways //    soundSettings.vibraMode = ProfileControl.VibraSilent //      soundSettings.vibraMode = ProfileControl.VibraNormal //      soundSettings.vibraMode = ProfileControl.VibraNever //    
Enable / disable sounds for system events
 import org.nemomobile.systemsettings 1.0 ProfileControl { id: soundSettings } soundSettings.systemSoundLevel = false //  soundSettings.systemSoundLevel = true //  
Enable / Disable WLAN
 import MeeGo.Connman 0.2 import com.jolla.settings 1.0 import com.jolla.connection 1.0 TechnologyModel { id: wifiListModel name: "wifi" } NetworkManagerFactory { id: networkManager } NetworkTechnology { id: wifiTechnology path: networkManager.instance.technologyPathForType("wifi") } ConnectionAgent { id: connectionAgent } checked: wifiListModel.available && wifiListModel.powered && !wifiTechnology.tethering if (wifiTechnology.tethering) connectionAgent.stopTethering(true) else wifiListModel.powered = !wifiListModel.powered 
Enable / Disable Internet Sharing
 import Sailfish.Telephony 1.0 import Sailfish.Silica.private 1.0 import MeeGo.Connman 0.2 import MeeGo.QOfono 0.2 import com.jolla.connection 1.0 ConnectionAgent { id: connectionAgent } NetworkManagerFactory { id: networkManager } NetworkTechnology { id: wifiTechnology path: networkManager.instance.technologyPathForType("wifi") } SimManager { id: simManager controlType: SimManagerType.Data } OfonoNetworkRegistration { id: networkRegistration modemPath: simManager.activeModem } OfonoConnMan { id: connectionManager modemPath: simManager.activeModem } function roamingDataAllowed() { return networkRegistration.valid && connectionManager.valid && !(networkRegistration.status === "roaming" && !connectionManager.roamingAllowed) } enabled: !networkManager.instance.offlineMode && (roamingDataAllowed() || wifiTechnology.tethering) if (wifiTechnology.tethering) { delayedTetheringSwitch.start() connectionAgent.stopTethering() } else { delayedTetheringSwitch.start() connectionAgent.startTethering("wifi") } 
Enable / Disable Flight Mode
 import MeeGo.Connman 0.2 NetworkManagerFactory { id: connMgr } connMgr.instance.offlineMode = true //  connMgr.instance.offlineMode = false //  
Turn on / off Bluetooth
 import MeeGo.Connman 0.2 import Sailfish.Bluetooth 1.0 import org.kde.bluezqt 1.0 as BluezQt TechnologyModel { id: btTechModel; name: "bluetooth" } btTechModel.powered = !btTechModel.powered //  


Basic system D-Bus features:
DescriptionRequired data
View calendar eventService:
com.jolla.calendar.ui
Way:
/com/jolla/calendar/ui
Interface:
com.jolla.calendar.ui
Function:
viewEvent(id, recurrenceId, startDate)
View the day on the calendarService:
com.jolla.calendar.ui
Way:
/com/jolla/calendar/ui
Interface:
com.jolla.calendar.ui
Function:
viewDate(dateTime)
Opening the camera in the last stateService:
com.jolla.camera
Way:
/
Interface:
com.jolla.camera.ui
Function:
showViewfinder()
Opening the front cameraService:
com.jolla.camera
Way:
/
Interface:
com.jolla.camera.ui
Function:
showFrontViewfinder()
Create alarmService:
com.jolla.clock
Way:
/
Interface:
com.jolla.clock
Function:
newAlarm()
View contactService:
com.jolla.contacts.ui
Way:
/com/jolla/contacts/ui
Interface:
com.jolla.contacts.ui
Function:
showContact(int contactId)
Editing a contactService:
com.jolla.contacts.ui
Way:
/com/jolla/contacts/ui
Interface:
com.jolla.contacts.ui
Function:
editContact(int contactId)
Importing contactsService:
com.jolla.contacts.ui
Way:
/com/jolla/contacts/ui
Interface:
com.jolla.contacts.ui
Function:
importWizard()
Play audio file by URLService:
com.jolla.mediaplayer
Way:
/com/jolla/mediaplayer/ui
Interface:
com.jolla.mediaplayer.ui
Function:
openUrl(url)
Create a new noteService:
com.jolla.notes
Way:
/
Interface:
com.jolla.notes
Function:
newNote()
View settingsService:
com.jolla.settings
Way:
/com/jolla/settings/ui
Interface:
com.jolla.settings.ui
Function:
showSettings()
View Download ListService:
com.jolla.settings
Way:
/com/jolla/settings/ui
Interface:
com.jolla.settings.ui
Function:
showTransfers()
View list of accountsService:
com.jolla.settings
Way:
/com/jolla/settings/ui
Interface:
com.jolla.settings.ui
Function:
showAccounts()
View call recording settingsService:
com.jolla.settings
Way:
/com/jolla/settings/ui
Interface:
com.jolla.settings.ui
Function:
showCallRecordings()
Enable / Disable Android SupportService:
com.jolla.apkd
Way:
/com/jolla/apkd
Interface:
com.jolla.apkd
Function:
controlService(true/false)
Turn on / off flashService:
com.jolla.settings.system.flashlight
Way:
/com/jolla/settings/system/flashlight
Interface:
com.jolla.settings.system.flashlight
Function:
toggleFlashlight()
Reboot deviceService:
com.nokia.dsme
Way:
/com/nokia/dsme/request
Interface:
com.nokia.dsme.request
Function:
req_reboot()
Turn off the deviceService:
com.nokia.dsme
Way:
/com/nokia/dsme/request
Interface:
com.nokia.dsme.request
Function:
req_shutdown
CallService:
com.jolla.voicecall.ui
Way:
/
Interface:
com.jolla.voicecall.ui
Function:
dial(number)
View images in the galleryService:
com.jolla.gallery
Way:
/com/jolla/gallery/ui
Interface:
com.jolla.gallery.ui
Function:
showImages(array_of_urls)
View Video GalleryService:
com.jolla.gallery
Way:
/com/jolla/gallery/ui
Interface:
com.jolla.gallery.ui
Function:
playVideoStream(url)
Create a new letterService:
com.jolla.email.ui
Way:
/com/jolla/email/ui
Interface:
com.jolla.email.ui
Function:
mailto()
Search for WLAN networksService:
com.jolla.lipstick.ConnectionSelector
Way:
/
Interface:
com.jolla.lipstick.ConnectionSelectorIf
Function:
openConnectionNow('wifi')


Questions and ideas arising in the course of development can always be discussed in the Telegram-chat and in the VKontakte group .

Source: https://habr.com/ru/post/337618/


All Articles