Archives For Invocation Framework

ekkes Express Charts is an application to create charts on-the-fly and can be integrated into BlackBerry EXPRESS.

Here’s an Overview about the APP and HowTo download und use.

Export / Import Charts…

…with a little help of Cascades Invokation Framework

Images of your charts are stored at the folder you defined from App – Settings, so you can easy send them to your friends or colleagues. But what about the data and all the properties and colors you set to create a good looking chart ?

This data is stored inside your APP’s sandbox, so it’s a safe place, but you cannot access it from other applications or File Manager.

The good news: I implemented an easy way to transfer the data without making it public visible.

If your friend doesn’t know about ‘ekkes Express Charts’ you can invite him / her easy from Home Page Action Bar via BBM.

Here’s the workflow if you want to send the data to a friend or colleague:

1. Exporting

Viewing or editing a single chart data you can export this one from Action Bar – Overflow menu:

chart_data_overflow_menu_export

Sending more then one chart data you can do a long-press on the List Page and select all the charts you want to export:

IMG_00000801

ekkes Express Charts will collect the data, create an attachment and open a predefined  Message Composer:

IMG_00000802_msg_comp

…all is done inside the app using Invocation Framework. See here to learn about invoking Core Apps like Message Composer.

2. Importing

Now on the other side where your friend gets your email:

IMG_00000034imp_att

As described in the body the only thing he / she has to do: Tap on the attached file and …

… by magic ‘ekkes Express Charts’ will be opened – doesn’t matter if it’s already running or not – and display this dialog to the user:

IMG_00000035imp_dialog

You will see how many data charts were sent and get a list of the titles to be sure it’s the right import file.

The application will add them all to the list of charts and update the UI of the List Page – doesn’t matter which Page you’re just working on. Your current workflow won’t be interrupted.

How is this ‘by-magic-open-the-app-from-an-email-attachment‘ done ? Again it’s the Invokation Framework !

I added the information into the bar-descriptor.xml:

<invoke-target id="org.ekkescorner.YOUR_UNIQUE_ID_HERE">
    <invoke-target-type>application</invoke-target-type>
    <invoke-target-name>ekkes Express Charts Import Data</invoke-target-name>
    <icon>
        <image>icon.png</image>
    </icon>
    <filter>
        <action>bb.action.OPEN</action>
        <mime-type>*</mime-type>
        <property var="exts" value="eecimp"/>
        <property var="uris" value="file://,data://"/>
    </filter>
</invoke-target>

Now if you click on a file with extension .eecimp ekkes Express Charts will be invoked :)

In your app you can detect if the app was launched by the user or if the app was invoked and then do what you want to do.

I told you that the data transfer was safe letting you data private. How is this done ?

Inside the application – sandbox all data is stored as JSON. (I wrote about using JSON a blog entry here)

If you take a look at the content of the .eecimp file you’ll see something like this:

{
   "exportedCharts" : "AwPuJ1JzovCJXJ.....4os370QllfA=="
}

It’s a JSON, but I scrambled the content with a key known by my app. So your data is protected and my app, too because if someone creates a fake .eecimp file it will open the app, but I can simply detect that I have to ignore the content.

Over all you see: with a little help of Invokation Framework you can create smooth workflows – not only inside your app – also between two apps as I demonstrated here.

This was only the first part of using Invokation Framework inside ‘ekkes Express Charts’ – read more about invoking my app from BlackBerry EXPRESS or 3rd party apps here: (TBD)

Try it out and have FUN.

Now my first Conferecne2Go APP for BlackBerry 10 is available at BlackBerry World:

Conference2Go EclipseCon

Z10-on-appworld

Search for ‘EclipseCon’ at BlackBerry World and download this app for FREE.

Thanks to Cascades Invocation Framework seamless integrated with

  • BBM
  • BlackBerry World
  • Foursquare
  • Twitter
  • Remember (Evernote)
  • MediaPlayer
  • ImageViewer

… to provide BlackBerry 10 FLOW

Read more about this app from my blogs, where you’ll also find many scereenshots:

EclipseCon and BlackBerry 10

Conference2Go APP at BlackBerry World

there’s also a first Video available:

http://vimeo.com/ekkescorner/c2g-eclipsecon

Download and have fun !(runs on Z10, DevALpha, Q10)

it’s FREE and there will follow more Conference Apps for BlackBerry 10: JAX, W-JAX, MTC, …

stay tuned…

Invoke Cards

November 8, 2012 — 1 Comment

The Invocation Framework allows you to develop a total new kind of apps. You can provide functionality to other apps or you can use functionality from other apps.

To understand what I’m talking about you should at first read the Cascades Documentation about App integration.

I will explain you how easy this can be done. You’ll find the code Open Source at Github:

For the target app (providing functionality) OpenDataSpace: https://github.com/blackberry/opendataspace-cascades

For the client app (using these functions) File Upload 2 ODS: https://github.com/OpenDataSpace/file-upload2ods

I will include some code-snippets in this post – to understand all what I’m doing there you should take a look at the sources I just mentioned.

The Target APP

OpenDataSpace is a full-blown-Application with a TabbedPane as Root and NavigationPanes + many Pages on top and also using an Application Menu.

The Application looks something like this:

To provide some functionality to other apps you can use “Cards”.

There are two different types of Cards:

  • Previewer: Like Pages pushed from NavigationPane (Sliding in from right, can be closed by peeking over a threshold)
  • Composer: Like Sheets (Sliding in from the bottom, cannot be closed from peek)

You don’t know the workflow of your clients and to support them best my tip: always provide both types: Previewer and Composer.

To invoke Cards using the Invocation Framework you have to describe them in the bar-descriptor.xml of your Target App like this:

<invoke-target id="io.ods.bb10.card.upload.previewer">
        <type>card.previewer</type>
        <invoke-target-name>Upload to ODS (Previewer)</invoke-target-name>
  		<icon>assets/images/upload-icon.png</icon>
        <filter>
            <action>bb.action.OPEN</action>
            <action>bb.action.SHARE</action>
      	    <mime-type>image/jpeg</mime-type>
      	    <mime-type>image/png</mime-type>
            ... your mime-types
        </filter>
    </invoke-target>

You need a unique invoke-target id, the type (card.previewer or card.composer), the action (in this case OPEN and SHARE) and one or more mime-types. I have defined some targets: a card.previewer, a card.composer and “APPLICATION”. Cards will be integrated in clients workflow – APPLICATION will open the target Application itself.

Inside your target app you can test from where your application was launched:

QString qmlDocument;
	switch (m_invokeManager->startupMode()) {
	case ApplicationStartupMode::LaunchApplication:
		// the normal Launch
		// our main QML document: the HomeScreen with a custom Background Image
		m_isLaunchedEmbedded = false;
		m_isCard = false;
		qmlDocument = "asset:///main.qml";
		qDebug() << "ApplicationStartupMode: LAUNCHED from homescreen";
		break;
	case ApplicationStartupMode::InvokeApplication:
		// Invocation. Someone Opened the App thru Invocation
		// our main QML document: the HomeScreen with a custom Background Image
		m_isLaunchedEmbedded = false;
		m_isCard = false;
		qmlDocument = "asset:///main.qml";
		qDebug() << "ApplicationStartupMode: LAUNCHED from Invocation";
		break;
	case ApplicationStartupMode::InvokeCard:
		// Card Opened by another App
		// the APP is now running embedded and invisible for the user
		// we only need a small part of the functionality,
		// so we use a different root object
		m_isLaunchedEmbedded = true;
		m_isCard = true;
		qmlDocument = "asset:///UploadCard.qml";
		qDebug() << "ApplicationStartupMode: LAUNCHED as CARD";
		break;
	default:
		// our main QML document: the HomeScreen with a custom Background Image
		m_isLaunchedEmbedded = false;
		m_isCard = false;
		qmlDocument = "asset:///main.qml";
		break;
	}

The most important decision: I’m using different documents as QML Root: main.qml for the full-blown app launched from Invocation or from Homescreen and Uploadcard.xml if launched as Card embedded into another app (the client-app).

Why am I doing this ? If launched embedded I only need a small part of the application:

My tip: only instantiate what you need ! Always think about performance and memory-footprint ! This is also important if you plan to get a certification “Built for BlackBerry 10

Using another root object as QML Document it looks much better:

If you’re providing more then one Card or you need different pages depending on the data you got from the client, then you can instantiate what you need lazy – but thats another story for a blog post.

Now I want to describe a sample workflow between two applications:

  • File Upload 2 ODS: the client app
  • OpenDataSpace: the target app

Both applications are available from BlackBerry AppWorld and the sources from Github – this should make it easy for you to follow.

The Client APP

File Upload 2 ODS is a simple App using Cascades FilePicker to browse files, select a file and the upload this file to the cloud. Instead of developing all the code by yourself you can use the UploadCard from OpenDataSpace.

The easiest way to get exactly what you need is to do a “bound invocation” – a bound invocation knows the target id where a unbound unvocation does a query and gets a list back for all targets providing something for a given mime-type.

To Invoke Card from the Client using a bound Invocation you can do it all from QML or you can do it from C++.

First step the user is doing: pick a file from FilePicker, then invoke the target app. (I will write another blog about the FilePicker, so we concentrate now on Invocation Framework)

This is the QML – way to embed a Card from target app:

InvokeActionItem {
            id: shareAction
            ActionBar.placement: ActionBarPlacement.OnBar
            query {
                // little trick: always use same mime type, because query needs a mime type
                // ODS then takes a look at file path suffix and ignores the mime-type
                mimeType: "image/png"
                invokeActionId: "bb.action.OPEN"
                invokeTargetId: "io.ods.bb10.card.upload.previewer"
            }
            onTriggered: {
                // next trick: all properties from query are read-only
                // but we can use the data, which is read-write to provide the URL
                data = picker.selectedFile
            }
        },

We’re using an InvokeActionItem and provide the Action (OPEN) and the target id.

Tip: We cannot do a bound invocation from InvokeActionItem out-of-the-box because a query is used and a query always needs a mime-type. The trick is to provide a valid mime-type of the target together with the target id – then only one result will be found. Another trick: all query-parameters are read-only, so we cannot use the URI to provide the file path – we’re using the data and fill the value in onTriggered {}
Here’s the C++ way to invoke the target. In QML we’re using a normal ActionItem and call the C++ function:

ActionItem {
            id: cloudActionPreviewer
            title: qsTr("Preview") + Retranslate.onLanguageChanged
            imageSource: "asset:///images/my.png"
            ActionBar.placement: ActionBarPlacement.OnBar
            onTriggered: {
                app.invokeBoundODSPreviewer(picker.selectedFile)
            }
        }

In C++ we only need some lines of code:

void FileUpload2ODS::invokeBoundODSPreviewer(QString data) {
	InvokeRequest cardRequest;
	cardRequest.setData(data.toLatin1());
	cardRequest.setTarget("io.ods.bb10.card.upload.previewer");
	m_invokeManager->invoke(cardRequest);
}

Now the request is sent to the Invocation Framework and the Card is invoked.

The target has to handle the invoke:

void OpenDataSpace::handleInvoke(const InvokeRequest& request) {
	m_invokationTarget = request.target();
	// Invoked as Application
	if (m_invokationTarget == "io.ods.bb10.invoke") {
		m_isCard = false;
	}
	// invoked as embedded Card (Previewer) from OPEN or SHARE
	else if (m_invokationTarget == "io.ods.bb10.card.upload.previewer") {
		m_isCard = true;
	}
	// invoked as embedded Card (Composer) from OPEN
	else if (m_invokationTarget == "io.ods.bb10.upload.composer") {
		m_isCard = true;
	}
	if (m_isCard) {
		AbstractPane *p = Application::instance()->scene();
		bool ok = false;
		if (request.uri().isEmpty()) {
			ok = p->setProperty("filePath", request.data());
		} else {
			ok = p->setProperty("filePath", request.uri());
		}
		if (ok) {
			// do some stuff
		}
	} else {
		// do what needed if Invoked, per ex. switch to a specific TAB
	}
}

Seemless Workflow

All Pages from the target are seamless integrated into the workflow :)
The User goes thru the Pages (provided by the Target App) and uploads the file to the cloud or he went back without uploading using the BACK Button or peeking over the threshold.

The Target App sends a ChildCardDone – signal and the client receives this in a slot. The signal includes a message with the reason and data, so you can check it easy and go on with the workflow or notify the user.

Here’s the Target APP Code if the Card is done:

void OpenDataSpace::cardDone() {
	CardDoneMessage message;
	message.setData(tr(":)"));
	message.setDataType("text/plain");
	message.setReason(tr("save"));
	m_invokeManager->sendCardDone(message);
}

There’s a similar code for cardCancelded.
The Client APP code receivong the ChildCardDone Signal in a Slot:

void FileUpload2ODS::childCardDone(const bb::system::CardDoneMessage &message) {
	// Card Child done with Success ?
	if (message.reason() == "save") {
		emit cardSuccess();
	} else {
		emit cardCanceled();
	}
	// now close the card !
	m_invokeManager->closeChildCard();
}

If you want to notify the UI (QML) you can send a Signal (cardSuccess / cardCanceled) where the Page is connected to.

You see: only less code is needed as glue code between the Invocation Framework and Target / Client APPs.

The best thing: the user doesn’t know that he used another app under the hood: the target app is invisible and the Card is embedded into the client app.

BTW: The Cascades FilePicker itself also uses the Invocation Framework: you’re getting a ChildCardDone Message with reason ‘save’ if the user selected a file and with reason ‘cancel’ if the user canceled. To make it easy to handle from the ChildCardDone I’m using the same reasons to let the client know what happened.

Some Screenshots

Here are some screenshots:

The Applications we’re using:

————

———

——

——

—–

—–

—–

—–

—–

—–

—–

—–

—–

—–

—–

—–

—-

The Video


(c) 2012 Creative Commons License 3.0 (BY-NC-SA) by ekkescorner