02-15-2013 03:15 AM
I had my app built with HTML5 for OS7, I'm building it for BB10 and I decided to go with a more native feel with Cascades. I have to admit though, the old WebWorks documentation was much wasier and friendly, you had a small example of how to use every functionality.
I'm having a problem getting the device's location, I went through the "Location diagnostics" sample app, but it's really complicated (it has like 3 classes of objects with a ton of features for getting the location).
I'm just trying to find the device's location, using cell towers, every couple of minutes. Do I have to create and entire class for that? Also, how do i trigger that function from the Cascades part?
I would really appreciate any help!
Solved! Go to Solution.
02-20-2013 03:02 PM
Hi,
Here's some simplified sample code. These files come from the default empty project template in the Momentix IDE (File -> New -> Project... -> BlackBerry Project -> Cascades Application -> Standard empty project). They have been modfied to include cellsite positioning updates every two minutes. The output simply goes through cout.
applicationui.h:
// Default empty project template
#ifndef ApplicationUI_HPP_
#define ApplicationUI_HPP_
#include <QObject>
#include <QtLocationSubset/QGeoPositionInfoSource>
using ::QtMobilitySubset::QGeoPositionInfo; // so the SIGNAL()/SLOT() macros can have matching signatures.
namespace bb { namespace cascades { class Application; }}
/*!
* @brief Application pane object
*
*Use this object to create and init app UI, to create context objects, to register the new meta types etc.
*/
class ApplicationUI : public QObject
{
Q_OBJECT
public:
ApplicationUI(bb::cascades::Application *app);
virtual ~ApplicationUI() {}
void startCellSiteUpdates();
public Q_SLOTS:
void positionUpdated(const QGeoPositionInfo & pos);
void positionUpdateTimeout();
private:
QtMobilitySubset::QGeoPositionInfoSource * _source;
};
#endif /* ApplicationUI_HPP_ */
applicationui.cpp
// Default empty project template #include "applicationui.hpp" #include <bb/location/PositionErrorCode> #include <bb/cascades/Application> #include <bb/cascades/QmlDocument> #include <bb/cascades/AbstractPane> #include <iostream> using namespace bb::cascades; ApplicationUI::ApplicationUI(bb::cascades::Application *app) : QObject(app) { // create scene document from main.qml asset // set parent to created document to ensure it exists for the whole application lifetime QmlDocument *qml = QmlDocument::create("asset:///main.qml").parent(th is); // create root object for the UI AbstractPane *root = qml->createRootObject<AbstractPane>(); // set created root object as a scene app->setScene(root); // Instantiate the default QGeoPositionInfoSource _source = QtMobilitySubset::QGeoPositionInfoSource::createDe faultSource(this); if ( _source ) {
// connect to the QGeoPositionInfoSource's signals, to get the position info and/or error status connect(_source, SIGNAL(positionUpdated(const QGeoPositionInfo &)), this, SLOT(positionUpdated(const QGeoPositionInfo &))); connect(_source, SIGNAL(updateTimeout()), this, SLOT(positionUpdateTimeout())); } }
// call this method to start the position updates void ApplicationUI::startCellSiteUpdates() { if ( !_source ) { std::cout << "Error getting default position info source" << std::endl; return; } // QtLocation allows control over which provider(s) will be queried for position info. NonSatellitePositioningMethods // includes wifi and cellsite fix types. _source->setPreferredPositioningMethods( QtMobilitySubset::QGeoPositionInfoSource::NonSatellitePositioningMethods ); // On BlackBerry the default QGeoPositionInfoSource allows finer control over the fix type. This extension, and others, take advantage of the Qt property system. // Here we are interested only in cellsite fixes. _source->setProperty("fixType", "cellsite"); // set the update interval to a couple of minutes. _source->setUpdateInterval(120000); // start the updates, which we expect to receive in ApplicationUI::positionUpdated() _source->startUpdates(); }
// slot connected to the QGeoPositionInfoSource::positionUpdated() signal void ApplicationUI::positionUpdated(const QGeoPositionInfo & pos) { // print out the position in a convenient format: std::cout << pos.coordinate().toString().toLatin1().constData() << std::endl; // print out the accuracy as well, if available if ( pos.hasAttribute(QtMobilitySubset::QGeoPositionInfo::HorizontalAccuracy) ) { std::cout << " horizontal accuracy = " << (double)pos.attribute(QtMobilitySubset::QGeoPositi onInfo::HorizontalAccuracy) << std::endl; } }
// slot connected to the QGeoPositionInfoSource::updateTimeout() signal void ApplicationUI::positionUpdateTimeout() { std::cout << "timeout occurred" << std::endl; // On BlackBerry more information as to why the device timed out may be available: bb::location::PositionErrorCode::Type errorCode = bb::location::PositionErrorCode::None; if ( _source->property("replyErrorCode").isValid() ) { errorCode = _source->property("replyErrorCode").value<bb::location::PositionErrorCode::Type>(); if ( errorCode != bb::location::PositionErrorCode::None ) { std::cout << " " << _source->property("replyErrStr").toString().toLati n1().constData() << std::endl; } } }
And main.cpp looks like this:
// Default empty project template
#include <bb/cascades/Application>
#include <QLocale>
#include <QTranslator>
#include "applicationui.hpp"
// include JS Debugger / CS Profiler enabler
// this feature is enabled by default in the debug build only
#include <Qt/qdeclarativedebug.h>
using namespace bb::cascades;
Q_DECL_EXPORT int main(int argc, char **argv)
{
// this is where the server is started etc
Application app(argc, argv);
// localization support
QTranslator translator;
QString locale_string = QLocale().name();
QString filename = QString( "SimpleLocation_%1" ).arg( locale_string );
if (translator.load(filename, "app/native/qm")) {
app.installTranslator( &translator );
}
ApplicationUI * appUI = new ApplicationUI(&app);
appUI->startCellSiteUpdates();
// we complete the transaction started in the app constructor and start the client event loop here
return Application::exec();
// when loop is exited the Application deletes the scene which deletes all its children (per qt rules for children)
}
Your bar-descriptor.xml file must contain this line to allow the app permission to location services:
<permission>access_location_services</permission>
Also ensure that Location Services are enabled, under Settings on your device.
Your .pro file must contain this line in order that the QtLocationSubset library is linked:
LIBS += -lQtLocationSubset
Hope this helps!
Jim
02-20-2013 03:39 PM - edited 02-20-2013 03:40 PM
If you're more of a web guy like me you can also try to use a WebView in your app with a small HTML page that fetches the GPS location the regular HTML5 way and then sends it to your QML through postMessage.
If the WebView contains code such as:
function sendCoords(position) {
var lat = Math.round(position.coords.latitude*10000)/10000;
var lon = Math.round(position.coords.longitude*10000)/10000;
navigator.cascades.postMessage('geodata:' + lat + ':' + lon);
}
navigator.geolocation.getCurrentPosition(sendCoord s);
Then in your QML you can have a WebView that loads the HTML doc with the above JS code on it. Something like:
attachedObjects: [
WebView {
id: locationgetter
url: "local:///assets/webview/getlocation.html"
onMessageReceived: {
if (message.data.match('geodata:')) {
lat = message.data.split(':')[1];
lon = message.data.split(':')[2];
// You have your latitude and longitude now!
// Do something with it...
}
}
}
]
I've had great success with this approach in my apps (Screamager and Scientific RPN Calculator) doing all sorts of things the HTML5 way that would normally require C++. It works very well!
Staff UI Prototyper (read: full-time hacker)
My BB10 apps: Screamager | Scientific RPN Calculator | The Last Weather App
02-20-2013 03:41 PM - edited 02-20-2013 03:43 PM
I have no idea why but the forum messed up my code and keeps doing so when I try to edit it.
Where it reads: geodata: it should actually read geodata: (with an actual colon rather than an entity)
Edit: AAARGH!!!! It keeps substituting my physical colon with a HTML5 entity.
Hope you understand what I'm trying to say.
Staff UI Prototyper (read: full-time hacker)
My BB10 apps: Screamager | Scientific RPN Calculator | The Last Weather App
02-23-2013 05:09 AM
Thanks jehrismann, this looks simple enough ![]()
One follow up question, so I'm pushing a page to show the location coordinates in the QML, how can I write the coordinates there from the positionUpdated() function?
@TheMarco, thanks for that option. Actually I am a web guy, but I'm trying to lear Cascades and go full on native for a better feel.
02-25-2013 03:36 PM
If you actually just want to access position info in QML (i.e. if you don't need position info in your C++ code), you can use the QtLocationSubset qml plugin. Here's a sample qml:
/* Copyright (c) 2012 Research In Motion Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Importing all our cascades functions. import bb.cascades 1.0 import QtMobilitySubset.location 1.1 Page { id: mainPage // A container is used to gather visual items together. Container { // A DockLayout is applied to the main container, this makes it // possible to layout controls and view inside the container. layout: DockLayout { } attachedObjects: [ TextStyleDefinition { id: tsd base: SystemDefaults.TextStyles.BodyText fontSize: FontSize.XSmall }, PositionSource { id: positionSource updateInterval: 1000 active: true } ] // The container containing the bubble image and text. Container { id: positionInfo layout: StackLayout { } Label {text: "<==== PositionSource ====>" textStyle { base: tsd.style } } Label {text: "positioningMethod: " + positionInfo.printableMethod(positionSource.positioningMethod) textStyle { base: tsd.style } } Label {text: "nmeaSource: " + positionSource.nmeaSource textStyle { base: tsd.style } } Label {text: "updateInterval: " + positionSource.updateInterval textStyle { base: tsd.style } } Label {text: "active: " + positionSource.active textStyle { base: tsd.style } } Label {text: "<==== Position ====>" textStyle { base: tsd.style } } Label {text: "timestamp: " + positionSource.position.timestamp textStyle { base: tsd.style } } Label {text: { var outStr = positionSource.position.latitudeValid ? positionSource.position.coordinate.latitude : "--" return "latitude: " + outStr } textStyle { base: tsd.style } } Label {text: { var outStr = positionSource.position.longitudeValid ? positionSource.position.coordinate.longitude : "--" return "longitude: " + outStr } textStyle { base: tsd.style } } Label {text: { var outStr = positionSource.position.horizontalAccuracyValid ? positionSource.position.horizontalAccuracy : "--" return "horizontal accuracy: " + outStr } textStyle { base: tsd.style } } Label {text: { var outStr = positionSource.position.altitudeValid ? positionSource.position.coordinate.altitude : "--" return "altitude: " + outStr } textStyle { base: tsd.style } } Label {text: { var outStr = positionSource.position.verticalAccuracyValid ? positionSource.position.verticalAccuracy : "--" return "vertical accuracy: " + outStr } textStyle { base: tsd.style } } Label {text: { var outStr = positionSource.position.speedValid ? positionSource.position.speed : "--" return "speed: " + outStr } textStyle { base: tsd.style } } function printableMethod(method) { if (method == PositionSource.SatellitePositioningMethod) return "Satellite"; else if (method == PositionSource.NoPositioningMethod) return "Not available" else if (method == PositionSource.NonSatellitePositioningMethod) return "Non-satellite" else if (method == PositionSource.AllPositioningMethods) return "All/multiple" return "source error"; } } } }
I'm not sure if the BB10 developer docs are up-to-date with information on this qml plugin, however it is a port of the official Qt Mobility 1.2 plugin, and the docs here should be relevant. Specifically, refer to the Coordinate, Position and PositionSource elements.
If you need to access data in qml and C++ then see the docs here.
Jim
02-26-2013 04:40 AM