Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Native Development

Reply
Developer
wantoun
Posts: 165
Registered: ‎10-04-2010
My Device: P'9982 & Z10
Accepted Solution

Getting the device's location

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!

Wadi
Please use plain text.
BlackBerry Development Advisor
jehrismann
Posts: 68
Registered: ‎10-15-2012
My Device: Z10

Re: Getting the device's location

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(this);

    // 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::createDefaultSource(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::QGeoPositionInfo::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().toLatin1().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

 

 

 

Please use plain text.
Developer
TheMarco
Posts: 669
Registered: ‎02-19-2011
My Device: BlackBerry PlayBook 32GB

Re: Getting the device's location

[ Edited ]

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&colon;' + lat + ':' + lon);
}

navigator.geolocation.getCurrentPosition(sendCoords);

 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&colon;')) {
                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

Please use plain text.
Developer
TheMarco
Posts: 669
Registered: ‎02-19-2011
My Device: BlackBerry PlayBook 32GB

Re: Getting the device's location

[ Edited ]

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&colon; it should actually read geodata&colon;  (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

Please use plain text.
Developer
wantoun
Posts: 165
Registered: ‎10-04-2010
My Device: P'9982 & Z10

Re: Getting the device's location

Thanks jehrismann, this looks simple enough :smileyhappy:

 

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.

Wadi
Please use plain text.
BlackBerry Development Advisor
jehrismann
Posts: 68
Registered: ‎10-15-2012
My Device: Z10

Re: Getting the device's location

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

Please use plain text.
Developer
wantoun
Posts: 165
Registered: ‎10-04-2010
My Device: P'9982 & Z10

Re: Getting the device's location

Thanks Jim, I actually need to process the location with C++ and apply some logic, but at the same time I need to display it to the user in QML.

My problem with the C++ was getting the location to a pushed screen (not the main one) in QML. But I guess that's another topic now, this solves my problem with getting the location.
Wadi
Please use plain text.
New Contributor
jayhuang75
Posts: 5
Registered: ‎07-07-2013
My Device: developer

Re: Getting the device's location

Hello TheMarco

I just try your way to get the location, but I keep getting this message:

QNXWebViewProvider::scrollPositionChanged()
QNXWebViewProvider::scrollPositionChanged() position=(0.000000, 0.000000)
QNXWebViewProvider::scrollPositionChanged()
QNXWebViewProvider::scrollPositionChanged() position=(0.000000, 0.000000)

Any idea about this!

Thank you so much
Please use plain text.
New Contributor
jayhuang75
Posts: 5
Registered: ‎07-07-2013
My Device: developer

Re: Getting the device's location

Hello Jim,

I just try your way to get the location but I always get the infos like this:

LocationManagerUtil.cpp:receiveReply(): ( 3 ) failed : Insufficient providers to satisfy request.
timeout occurred
Insufficient providers to satisfy request.

I just to google it but no lucky to get solution, can you guide me to the right position?

Thank you and have a nice day
Please use plain text.
New Contributor
jayhuang75
Posts: 5
Registered: ‎07-07-2013
My Device: developer

Re: Getting the device's location

Ok, I think I found the answer about how to get the location in native way.

 

Check this http://supportforums.blackberry.com/t5/Cascades-Development/About-GPS-Location-Listening-implementat...

 

Thank you guys anyway!

Please use plain text.