Files:
The Invoke Target example shows how to handle incoming invocation requests from other applications.
In this example we'll learn how to use the InvokeManager and InvokeRequest classes of the BB10 framework to handle incoming invocation requests from external applications.
All the business logic is encapsulated in the C++ class App, which is exported to the QML files under the name '_app'.
The UI of this sample application consists of a main page which displays a hint paragraph with a few examples on how to use this application, this display comes up when launched as an application.
In addition, there are three new pages (Composer, Picker and Previewer), which are launched when their bound target id's are invoked via the invokeclient sample application. All three are registerd and invoked as "Cards".
The Composer page consists of an TextArea with two button actions (cancel and share), which cancel the current task or mimick sharing option.
NavigationPane { backButtonsVisible: false peekEnabled: true Page { titleBar: TitleBar { title: qsTr("Composer") acceptAction: ActionItem { title: qsTr("Share") onTriggered: { _app.cardDone(qsTr("Content Shared.")); } } dismissAction: ActionItem { title: qsTr("Cancel") onTriggered: { _app.cardDone(qsTr("Dont feel like sharing today?")); } } } Container { horizontalAlignment: HorizontalAlignment.Fill Header { title: qsTr("Share via Sample Composer") } Container { horizontalAlignment: HorizontalAlignment.Fill TextArea { horizontalAlignment: HorizontalAlignment.Center preferredHeight: 400 text: _app.data onCreationCompleted: { requestFocus(); } } } } } }
The Picker page displays many egg images and asks the user to pick one when invoked.
NavigationPane { backButtonsVisible: false peekEnabled: true Page { titleBar: TitleBar { title: qsTr("Pick an Egg") dismissAction: ActionItem { title: qsTr("Cancel") onTriggered: { _app.cardDone(qsTr("Boo! No eggs today..")); } } } Container { layout: DockLayout { } horizontalAlignment: HorizontalAlignment.Fill ImageButton { horizontalAlignment: HorizontalAlignment.Left verticalAlignment: VerticalAlignment.Top defaultImageSource: "asset:///images/egg.png" onClicked: { _app.cardDone(qsTr("Yummy!")); } } ImageButton { horizontalAlignment: HorizontalAlignment.Center verticalAlignment: VerticalAlignment.Top defaultImageSource: "asset:///images/egg.png" onClicked: { _app.cardDone(qsTr("Quack Quack..")); } } ImageButton { horizontalAlignment: HorizontalAlignment.Right verticalAlignment: VerticalAlignment.Top defaultImageSource: "asset:///images/egg.png" onClicked: { _app.cardDone(qsTr("Mmmmmm..")); } } ImageButton { horizontalAlignment: HorizontalAlignment.Left verticalAlignment: VerticalAlignment.Center defaultImageSource: "asset:///images/egg.png" onClicked: { _app.cardDone(qsTr("Delicio!")); } } ImageButton { horizontalAlignment: HorizontalAlignment.Center verticalAlignment: VerticalAlignment.Center defaultImageSource: "asset:///images/egg.png" onClicked: { _app.cardDone(qsTr("Yuck!")); } } ImageButton { horizontalAlignment: HorizontalAlignment.Right verticalAlignment: VerticalAlignment.Center defaultImageSource: "asset:///images/egg.png" onClicked: { _app.cardDone(qsTr("Whoa!")); } } ImageButton { horizontalAlignment: HorizontalAlignment.Left verticalAlignment: VerticalAlignment.Bottom defaultImageSource: "asset:///images/egg.png" onClicked: { _app.cardDone(qsTr("Love it..")); } } ImageButton { horizontalAlignment: HorizontalAlignment.Center verticalAlignment: VerticalAlignment.Bottom defaultImageSource: "asset:///images/egg.png" onClicked: { _app.cardDone(qsTr("Get it cooked already!")); } } ImageButton { horizontalAlignment: HorizontalAlignment.Right verticalAlignment: VerticalAlignment.Bottom defaultImageSource: "asset:///images/egg.png" onClicked: { _app.cardDone(qsTr("Sunny side up")); } } } } }
The Previewer page displays the image with which it was invoked using the uri variable that was passed through the invocation request.
NavigationPane { backButtonsVisible: true peekEnabled: true Page { titleBar: TitleBar { title: qsTr("Previewer") } Container { horizontalAlignment: HorizontalAlignment.Fill ImageView { imageSource: _app.uri scalingMethod: ScalingMethod.AspectFit } } } }
The App object is the mediator between the UI and the bb::system::InvokeManager class. In stores the startup mode and values of incoming invocation requests and makes them available to the UI through properties.
class App : public QObject { Q_OBJECT // The textual representation of the startup mode of the application Q_PROPERTY(QString startupMode READ startupMode NOTIFY requestChanged) // The values of the incoming invocation request Q_PROPERTY(QString source READ source NOTIFY requestChanged) Q_PROPERTY(QString target READ target NOTIFY requestChanged) Q_PROPERTY(QString action READ action NOTIFY requestChanged) Q_PROPERTY(QString mimeType READ mimeType NOTIFY requestChanged) Q_PROPERTY(QString uri READ uri NOTIFY requestChanged) Q_PROPERTY(QString data READ data NOTIFY requestChanged) // The textual representation of the card status Q_PROPERTY(QString status READ status NOTIFY statusChanged) public: App(QObject *parent = 0); void initFullUI(); void initComposerUI(); void initPreviewerUI(); void initPickerUI(); public Q_SLOTS: // This method is invoked to notify the invocation system that the action has been done void cardDone(const QString& msg); Q_SIGNALS: // The change notification signal of the properties void requestChanged(); void statusChanged(); private Q_SLOTS: // This slot is called whenever an invocation request is received void handleInvoke(const bb::system::InvokeRequest&); void resized(const bb::system::CardResizeMessage&); /** * This slot is triggered when a card is chosen to be pooled by the system after it is closed. The card should clear it's UI * and states so that it is ready for the next invocation. */ void pooled(const bb::system::CardDoneMessage&); private: // The accessor methods of the properties QString startupMode() const; QString source() const; QString target() const; QString action() const; QString mimeType() const; QString uri() const; QString data() const; QString status() const; // The central class to manage invocations bb::system::InvokeManager *m_invokeManager; // The property values QString m_startupMode; QString m_source; QString m_target; QString m_action; QString m_mimeType; QString m_uri; QString m_data; QString m_status; };
Inside the constructor the member variables are initialized with default values and the UI is loaded from the main.qml file.
App::App(QObject *parent) : QObject(parent) , m_invokeManager(new InvokeManager(this)) { // Listen to incoming invocation requests bool ok = connect(m_invokeManager, SIGNAL(invoked(const bb::system::InvokeRequest&)), this, SLOT(handleInvoke(const bb::system::InvokeRequest&))); Q_ASSERT(ok); ok = connect(m_invokeManager, SIGNAL(cardResizeRequested(const bb::system::CardResizeMessage&)), this, SLOT(resized(const bb::system::CardResizeMessage&))); Q_ASSERT(ok); ok = connect(m_invokeManager, SIGNAL(cardPooled(const bb::system::CardDoneMessage&)), this, SLOT(pooled(const bb::system::CardDoneMessage&))); Q_ASSERT(ok); m_source = m_target = m_action = m_mimeType = m_uri = m_data = m_status = tr("--"); // Initialize properties with default values switch (m_invokeManager->startupMode()) { case ApplicationStartupMode::LaunchApplication: m_startupMode = tr("Launch"); initFullUI(); break; case ApplicationStartupMode::InvokeApplication: // Wait for invoked signal to determine and initialize the appropriate UI m_startupMode = tr("Invoke"); break; case ApplicationStartupMode::InvokeCard: // Wait for invoked signal to determine and initialize the appropriate UI m_startupMode = tr("Card"); break; } // Create the UI }
To get informed about incoming invocation requests, the custom slot handleInvoke() is connected against the invoked() signal of the bb::system::InvokeManager object.
void App::handleInvoke(const InvokeRequest& request) { // Copy data from incoming invocation request to properties m_source = QString::fromLatin1("%1 (%2)").arg(request.source().installId()).arg( request.source().groupId()); m_target = request.target(); m_action = request.action(); m_mimeType = request.mimeType(); m_uri = request.uri().toString(); m_data = QString::fromUtf8(request.data()); if (m_target == "com.example.bb10samples.invocation.sharecomposer") { initComposerUI(); } else if (m_target == "com.example.bb10samples.invocation.imagepreviewer") { initPreviewerUI(); } else if (m_target == "com.example.bb10samples.invocation.eggpicker") { initPickerUI(); } // Signal that the properties have changed emit requestChanged(); }
The values from the passed bb::system::InvokeRequest are copied to the property values and the UI is updated by emitting the change notification signal.
To make the invoketarget application a candidate for invocations, the BB10 system must know about the invocation interface of the application. That is defined inside the bar-descriptor.xml file of the project inside an invoke-target element.
<invoke-target id="com.example.bb10samples.invocation.openimage1"> <invoke-target-name>InvokeTarget Image 1</invoke-target-name> <icon><image>icon.png</image></icon> <type>application</type> <filter> <action>bb.action.OPEN</action> <mime-type>image/png</mime-type> </filter> </invoke-target> <invoke-target id="com.example.bb10samples.invocation.openimage2"> <invoke-target-name>InvokeTarget Image 2</invoke-target-name> <icon><image>icon.png</image></icon> <type>application</type> <filter> <action>bb.action.OPEN</action> <mime-type>image/png</mime-type> </filter> </invoke-target> <invoke-target id="com.example.bb10samples.invocation.card.previewer"> <type>card.previewer</type> <filter> <action>bb.action.OPEN</action> <mime-type>image/png</mime-type> </filter> </invoke-target> <invoke-target id="com.example.bb10samples.invocation.card.composer"> <type>card.composer</type> <filter> <action>bb.action.OPEN</action> <mime-type>image/png</mime-type> </filter> </invoke-target> <invoke-target id="com.example.bb10samples.invocation.card.picker"> <type>card.picker</type> <filter> <action>bb.action.OPEN</action> <mime-type>image/png</mime-type> </filter> </invoke-target>