Saturday 3 October 2015

Reliable way to get current location using ngCordova

Usual approach

As you can see from ngCordova documentation found here, the use of getCurrentPosition is most likely the easier way of getting current location. It looks like if the enableHighAccuracy to true could increase the possibity of getting a reliable current location.

I was working on my first IONIC app where i wanted to get the current location during the absence of internet.I started testing by trying to get the current location while roaming around and once i had a WIFI connection i was trying to verify captured location.

Results were not consistence and have even tried changing argument values but none gave consistence results. When searching out a but it appears like the results are coming out of a cached GPS values. Below is an approach where by repeatedly using the watchPosition gave better results.

Using watchPosition instead of getCurrentPosition

As there is an accuracy returned from the GeoLocation API the plan is to keep retrying till the desired level of accuracy is obtained. This retry time and interval would need to be configuration so that that i can be controlled a bit.

I have written a factory service for now it has only getCurrentPosition. We can expand it later.

Step 1
Delegate the call to a private method which will attempt to get a reliable location and as its asynchronous, we need to return a promise back so that the calling code can monitor that. 

Code
   return {  
     getCurrentLocation : function (options) {  
       var deferred = $q.defer();  
       callStart = new Date().getTime() / 1000;  
       _getLocationWrapper({callStart:callStart,  
                  deferred:deferred,  
                  othOptions:options,  
                  attempt:1});  
       return deferred.promise;  
     }  
   };  


The "options" that needs to be used for watchPosition are taken as input but are also passed over with "othOptions". Other parameters used are self contained within the service method.

Step 2
A wrapper method is created for handling first invocation of the service method

Code
   function _getLocationWrapper(options) {  
      var locCB=function(){return _getLocation(options);};  
      if ( options.attempt == 1 ) {  
        locCB();  
      } else {  
       setTimeout(locCB, options.othOptions.gps.interval*1000);  
      }  
   }  


Step 3
Calls the $cordovaGeolocation.watchPosition and in the callback of that 

When error, return back the error too.

When success,  

  • Check for the desired accuracy and if achieved then return back same or callback the wrapper again.
  • If timeout is reached but the desired accuracy is not obtained then feedback that as error.

In all the processing feedback to client on the progress/retries using deferred's "notify"


Code
   function _getLocation(options){  
     var callStart = options.callStart;  
     var deferred  = options.deferred;  
     var attempt  = options.attempt;  
     var othOptions = options.othOptions;  
     deferred.notify({attempt: attempt, message:'Searching attempt '+attempt, lastAccuracy : options.lastAccuracy});  
     var getLocOptions = {  
       enableHighAccuracy: othOptions.gps.enableHighAccuracy,  
       timeout: othOptions.gps.timeout * 100,  
       maximumAge: 0  
     };  
     var locWatch = $cordovaGeolocation.watchPosition(getLocOptions);  
     locWatch.then(  
       null,  
       function(err) {  
         locWatch.clearWatch();  
         deferred.reject({err:err});  
       },  
       function(position) {  
         var callEnd = new Date().getTime() / 1000;  
         locWatch.clearWatch();  
         if ( position.coords.accuracy && position.coords.accuracy <= othOptions.gps.accuracy ) {  
           // This is good accuracy then accept it  
           deferred.resolve({status:0, position:position});  
         } else if ( (callEnd - callStart) < othOptions.gps.timeout ) {  
           // Keep trying till the configured wait time. If exceeds then return back.  
           options.attempt++;  
           options.lastAccuracy = Math.round(position.coords.accuracy * 100) / 100;  
           options.minAccuracy = options.minAccuracy || options.lastAccuracy; // Default  
           options.minAccuracy = options.minAccuracy < options.lastAccuracy ? options.lastAccuracy : options.minAccuracy;  
           _getLocationWrapper(options);  
         } else {  
           deferred.reject( {error:{code:-999, message:"Could not get location.<br>Minimum accuracy is "+options.minAccuracy+" mts.<br>Try to check location in open area or try adjusting to acceptable accuracy."}} );  
         }  
       }  
     );  
   }  

Step 4
Finally client invocation 


Code


     var locationService = GSSearchLocationService.getCurrentLocation(  
       {  
         enableHighAccuracy : true,   
         timeout : 120, // In seconds  
         interval : 5,  // Retry interval in seconds  
         accuracy : 15  // Accuracy distance in meters   
       }  
     );  
     locationService.then(  
       function(options) {  
        // put your success callback  
       },  
       function(options) {  
        // put your error callback  
       },  
       function(notificationData) {  
         // Put your retry notification messages  
         // Example showing a Ionic Loading message  
         // $ionicLoading.show({  
         //  template: 'Getting Current Position...'  
         //   + '<br>Attempts : '+notificationData.attempt+' <br>Accurracy(m) : '  
         //   + notificationData.lastAccuracy  
         // });  
       }  
      );  


Download


Full service code can be downloaded from here and kindly modify it accordingly.


Sunday 27 September 2015

Showcasing IONIC Framework : Developed a Location Book with integration with Sygic, Google Maps API with Clipboard and ShareTo plugin

What is Location Book?


  • Its an hybrid app and is built on IONIC
  • Get and store current location (offline)
  • Search for locations (online) and store them to be used later for offline navigation.
  • Search a place and view details (when online)
  • Store the locations with custom name
  • Sygic Companion
  • Share the location
  • Copy location position to clipboard (Can be pasted in other apps e.g. Google Maps)
Location Book mobile app build powered by IONIC, Cordova  and Google

Tabs (Row #1, Col #1) 

  • Home Page – Have all the saved location
  • Search – Search for a place or address (This is Powered by Google Search and optional MAPS API, if you add an API Key)
  • Options – Application settings and current location finder.

Search (Row #1, Col #1)  


  • Location / Place / Address Search Bar (#1)
  • Show Search Results
  • Ability to add to Saved List (#2)
  • Ability to open Sygic (Car Icon in #2)
  • Optionally MAPS API keys can be generated and used to provide better search results.

Details Page (Row #1, Col #2, #3) 

As shown in Pic #3 and  #4 

  • Shows a details of the search out address / saved address.
  • Location name can be customized.
  • Location address can be edited.
  • Location can be shared to other applications. (#10)
  • Location data can be copied to clipboard.
  • Location can be added to saved list.
  • Location static map is shown. (Powered by Google)

Saved Locations (Row #2 Col #2, #3) 

  • Shows the list of saved location (#5)
  • List can be rearranged (#6)

Options (Row #3 ) 

  • Current location position details can be obtained  (#8)
  • GPS Settings can be tweaked (#11)
  • Its recommended to add a MAPS API key for better search results (#7)

Current Location (Row #3, Col #2, #3) 

Having data (or Internet Connectivity) is not necessary
  • Current location position details can be obtained  (#9)
  • Current location address can be edited and a meaning full name can be given
  • Share your location to others or store it

Code


Only the www folder of the  IONIC app has been placed in GitHub

Ionic Plugins installed are
com.ionic.keyboard 1.0.4 "Keyboard"
com.verso.cordova.clipboard 0.1.0 "Clipboard"
cordova-plugin-console 1.0.1 "Console"
cordova-plugin-device 1.0.1 "Device"
cordova-plugin-geolocation 1.0.2-dev "Geolocation"
cordova-plugin-inappbrowser 1.0.1 "InAppBrowser"
cordova-plugin-splashscreen 2.1.0 "Splashscreen"
cordova-plugin-whitelist 1.0.0 "Whitelist"
nl.x-services.plugins.socialsharing 4.3.20-dev "SocialSharing"



Download

Feel free to download the APK of this mobile app.
Feel free to refer to code in GitHub


TO DO

  • Need to build grouping the location.
  • Need to Export/Import the locations.
  • Try a reverse geo coding for “Where am I?” i.e. Get Current Location

Thanks To

Thanks to 

  • Google
  • Ionic Framework
  • Cordova
  • AngularJS
  • Sygic
  • All the developer for all sharing knowledge, tools, plugins and API’s