Tutorial: get current gps position

towski edited this page Jan 31, 2014 · 8 revisions

Goal

Retrieve the current GPS position of the device, or indicate that we have no GPS hardware or no fix.

Prerequisites

You should have completed the Getting started with Ruboto tutorial. To get any interresting results, you should use a device with GPS and have a fix.

This tutorial has been tested with the following setups

Platform JDK JRuby ruboto Device API level
OS X 1.7.0_45 RubotoCore 0.5.6 1.0.0 Samsung Galaxy S3 >. 16
OS X 1.7.0_15 RubotoCore 0.5.3 0.11.0 Samsung Galaxy S3 >. 16
OS X 1.6.0_33 RubotoCore 0.4.7 0.8.0 Htc Desire HD >. 10
OS X 1.6.0_33 RubotoCore 0.4.7 0.8.0 Htc Desire S >. 10
OS X 1.6.0_33 RubotoCore 0.4.7 0.8.0 Emulator >. 16

Create the app and install it

Connect your device or start the emulator.

ruboto gen app --package org.ruboto.example.gps
cd gps
rake install start

You should see the standard "What hath Matz wrought?" screen.

A fresh app

Code

Edit src/gps_activity.rb to this:

require 'ruboto/widget'
require 'ruboto/util/toast'
require 'address_finder'

ruboto_import_widgets :LinearLayout, :TextView

java_import 'android.content.Context'
java_import 'android.location.LocationManager'
java_import 'android.content.Intent'
java_import 'android.net.Uri'

class GpsActivity
  def onCreate(bundle)
    super
    setTitle 'Ruboto GPS Example'

    @lm = getSystemService(Context::LOCATION_SERVICE)
    @ll = MyLocationListener.new(self)

    self.content_view = linear_layout :orientation => :vertical do
      linear_layout do
        text_view :text => 'Time: ', :id => 42
        @time_view = text_view :text => ''
      end
      linear_layout do
        text_view :text => 'Lat: '
        @lat_view = text_view :text => ''
      end
      linear_layout do
        text_view :text => 'Lng: '
        @lng_view = text_view :text => ''
      end
      linear_layout do
        text_view :text => 'Address: '
        @address_view = text_view :text => ''
      end
    end
  end

  def onResume
    super
    @lm.requestLocationUpdates(LocationManager::GPS_PROVIDER, 1000, 5, @ll)    
  end
  
  def onPause
    super
    Thread.start{@lm.removeUpdates @ll}
  end

  def update_location(location)
    @time_view.text = Time.at(location.time / 1000).strftime('%Y-%m-%d %H:%M:%S')
    @lat_view.text = location.latitude.to_s
    @lng_view.text = location.longitude.to_s
    if @last_request.nil? || (Time.now - @last_request) > 60
      toast "Location: #{location.time} #{location.latitude} #{location.longitude}"
      @last_request = Time.now
      AddressFinder.find_address(self, location)
    end
  end

  def update_address(address)
    run_on_ui_thread do
      @address_view.text = address
      toast "Address: #{address}"
    end
  end

  def update_address_failed(message)
    run_on_ui_thread do
      toast "Address update failed: #{message}"
    end
  end
end

class MyLocationListener
  def initialize(activity)
    @activity = activity
  end

  # Required on the Java side when registered
  def hashCode
    hash
  end
  
  def onLocationChanged(location)
    @activity.update_location(location)
  end

  def onProviderDisabled(provider)
  end

  def onProviderEnabled(provider)
  end

  def onStatusChanged(provider, status, extras)
  end
end

Add permission to get the location and to access the Internet to the AndroidManifest.xml file, just below the uses-sdk tag:

	<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
	<uses-permission android:name="android.permission.INTERNET" />

Create src/address_finder.rb:

require 'ruboto/util/stack'
require 'yaml'

java_import 'android.net.http.AndroidHttpClient'
java_import 'org.apache.http.client.methods.HttpGet'
java_import 'org.apache.http.util.EntityUtils'

class AddressFinder
  def self.find_address(activity, location)
    Thread.with_large_stack do
      begin
        puts '#' * 80
        puts 'Connecting to Google'
        puts '#' * 80
        client = AndroidHttpClient.newInstance('eurucamp2012')
        method = HttpGet.new("http://maps.googleapis.com/maps/api/geocode/json?latlng=#{location.latitude},#{location.longitude}&sensor=true")
        if response = EntityUtils.toString(client.execute(method).entity)
          address = YAML.load(response)['results'][0]['formatted_address']
          activity.update_address(address)
        else
          activity.update_address_failed('Request failed!')
        end
      rescue Exception
        puts 'Exception during request'
        puts "Exception during request: #{$!.class} #{$!.message}\n#{$!.backtrace.join("\n")}"
        activity.update_address_failed('Exception during request', $!)
      ensure
        client.close if client
      end
    end
  end
end

Redeploy the application with new scripts

rake install start

You should now receive an updated location when it changes by 5 meters, and an updated address every minute.

Clone this wiki locally
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.