Get location with GeoClue2

This commit is contained in:
André Apitzsch 2017-12-03 14:59:52 +01:00
parent 2a2217b80e
commit 2aab433932
4 changed files with 77 additions and 111 deletions

View File

@ -231,6 +231,13 @@ try:
except (ImportError, ValueError): except (ImportError, ValueError):
HAVE_FARSTREAM = False HAVE_FARSTREAM = False
HAVE_GEOCLUE = True
try:
gi.require_version('Geoclue', '2.0')
from gi.repository import Geoclue
except (ImportError, ValueError):
HAVE_GEOCLUE = False
HAVE_UPNP_IGD = True HAVE_UPNP_IGD = True
try: try:
gi.require_version('GUPnPIgd', '1.0') gi.require_version('GUPnPIgd', '1.0')

View File

@ -19,14 +19,21 @@
## ##
from datetime import datetime from datetime import datetime
import logging
from gajim.common import app from gajim.common import app
from gajim.common import dbus_support
if dbus_support.supported: import gi
import dbus gi.require_version('Geoclue', '2.0')
from gi.repository import Geoclue
from gi.repository import GLib
log = logging.getLogger('gajim.c.location_listener')
class LocationListener: class LocationListener:
_instance = None _instance = None
@classmethod @classmethod
def get(cls): def get(cls):
if cls._instance is None: if cls._instance is None:
@ -36,89 +43,41 @@ class LocationListener:
def __init__(self): def __init__(self):
self._data = {} self._data = {}
def get_data(self): def _on_location_update(self, simple):
bus = dbus.SessionBus() location = simple.get_location()
timestamp = location.get_property("timestamp")[0]
lat = location.get_property("latitude")
lon = location.get_property("longitude")
alt = location.get_property("altitude")
# in XEP-0080 it's horizontal accuracy
acc = location.get_property("accuracy")
# update data with info we just received
self._data = {'lat': lat, 'lon': lon, 'alt': alt, 'accuracy': acc}
self._data['timestamp'] = self._timestamp_to_utc(timestamp)
self._send_location()
def _on_simple_ready(self, obj, result):
try: try:
# Initializes Geoclue. self.simple = Geoclue.Simple.new_finish(result)
obj = bus.get_object('org.freedesktop.Geoclue.Master', except GLib.Error as e:
'/org/freedesktop/Geoclue/Master') if e.domain == 'g-dbus-error-quark':
# get MasterClient path log.warning("Could not enable geolocation: %s", e.message)
path = obj.Create() else:
# get MasterClient raise
cli = bus.get_object('org.freedesktop.Geoclue.Master', path) else:
cli.SetRequirements(1, 0, True, 1023) self.simple.connect('notify::location', self._on_location_update)
self._on_location_update(self.simple)
self._get_address(cli) def get_data(self):
self._get_position(cli) Geoclue.Simple.new("org.gajim.Gajim",
except: Geoclue.AccuracyLevel.EXACT,
self._on_geoclue_position_changed() None,
return self._on_simple_ready)
def _get_address(self, cli):
bus = dbus.SessionBus()
cli.AddressStart()
# Check that there is a provider
name, description, service, path = cli.GetAddressProvider()
if path:
provider = bus.get_object(service, path)
timestamp, address, accuracy = provider.GetAddress()
self._on_geoclue_address_changed(timestamp, address, accuracy)
def _get_position(self, cli):
bus = dbus.SessionBus()
cli.PositionStart()
# Check that there is a provider
name, description, service, path = cli.GetPositionProvider()
if path:
provider = bus.get_object(service, path)
fields, timestamp, lat, lon, alt, accuracy = provider.GetPosition()
self._on_geoclue_position_changed(fields, timestamp, lat, lon, alt,
accuracy)
def start(self): def start(self):
self.location_info = {} self.location_info = {}
self.get_data() self.get_data()
bus = dbus.SessionBus()
# Geoclue
bus.add_signal_receiver(self._on_geoclue_address_changed,
'AddressChanged', 'org.freedesktop.Geoclue.Address')
bus.add_signal_receiver(self._on_geoclue_position_changed,
'PositionChanged', 'org.freedesktop.Geoclue.Position')
def shut_down(self):
pass
def _on_geoclue_address_changed(self, timestamp=None, address=None,
accuracy=None):
# update data with info we just received
if address is None:
address = {}
for field in ['country', 'countrycode', 'locality', 'postalcode',
'region', 'street']:
self._data[field] = address.get(field, None)
if timestamp:
self._data['timestamp'] = self._timestamp_to_utc(timestamp)
if accuracy:
# in PEP it's horizontal accuracy
self._data['accuracy'] = accuracy[1]
self._send_location()
def _on_geoclue_position_changed(self, fields=None, timestamp=None, lat=None,
lon=None, alt=None, accuracy=None):
if fields is None:
fields = []
# update data with info we just received
_dict = {'lat': lat, 'lon': lon, 'alt': alt}
for field in _dict:
if _dict[field] is not None:
self._data[field] = _dict[field]
if timestamp:
self._data['timestamp'] = self._timestamp_to_utc(timestamp)
if accuracy:
# in PEP it's horizontal accuracy
self._data['accuracy'] = accuracy[1]
self._send_location()
def _send_location(self): def _send_location(self):
accounts = app.connections.keys() accounts = app.connections.keys()
@ -143,10 +102,7 @@ class LocationListener:
time = datetime.utcfromtimestamp(timestamp) time = datetime.utcfromtimestamp(timestamp)
return time.strftime('%Y-%m-%dT%H:%MZ') return time.strftime('%Y-%m-%dT%H:%MZ')
def enable(): def enable():
listener = LocationListener.get() listener = LocationListener.get()
listener.start() listener.start()
def disable():
listener = LocationListener.get()
listener.shut_down()

View File

@ -57,9 +57,11 @@ from gajim.common import events
from gajim.common import dbus_support from gajim.common import dbus_support
if dbus_support.supported: if dbus_support.supported:
from gajim.music_track_listener import MusicTrackListener from gajim.music_track_listener import MusicTrackListener
from gajim.common import location_listener
import dbus import dbus
if app.HAVE_GEOCLUE:
from gajim.common import location_listener
from gajim import gtkgui_helpers from gajim import gtkgui_helpers
from gajim import gui_menu_builder from gajim import gui_menu_builder
from gajim import dialogs from gajim import dialogs
@ -1118,15 +1120,14 @@ class Interface:
if connected == invisible_show: if connected == invisible_show:
return return
# send currently played music # send currently played music
if obj.conn.pep_supported and dbus_support.supported and \ if (obj.conn.pep_supported and dbus_support.supported and
app.config.get_per('accounts', account, 'publish_tune'): app.config.get_per('accounts', account, 'publish_tune')):
self.enable_music_listener() self.enable_music_listener()
# enable location listener # enable location listener
if obj.conn.pep_supported and dbus_support.supported and \ if (obj.conn.pep_supported and app.HAVE_GEOCLUE and
app.config.get_per('accounts', account, 'publish_location'): app.config.get_per('accounts', account, 'publish_location')):
location_listener.enable() location_listener.enable()
@staticmethod @staticmethod
def handle_event_metacontacts(obj): def handle_event_metacontacts(obj):
app.contacts.define_metacontacts(obj.conn.name, obj.meta_list) app.contacts.define_metacontacts(obj.conn.name, obj.meta_list)

View File

@ -64,7 +64,8 @@ from gajim.common import app
from gajim.common import helpers from gajim.common import helpers
from gajim.common.exceptions import GajimGeneralException from gajim.common.exceptions import GajimGeneralException
from gajim.common import i18n from gajim.common import i18n
from gajim.common import location_listener if app.HAVE_GEOCLUE:
from gajim.common import location_listener
from gajim.common import ged from gajim.common import ged
from gajim.common import dbus_support from gajim.common import dbus_support
from gajim.message_window import MessageWindowMgr from gajim.message_window import MessageWindowMgr
@ -3647,12 +3648,6 @@ class RosterWindow:
location_listener.enable() location_listener.enable()
else: else:
app.connections[account].retract_location() app.connections[account].retract_location()
# disable music listener only if no other account uses it
for acc in app.connections:
if app.config.get_per('accounts', acc, 'publish_location'):
break
else:
location_listener.disable()
helpers.update_optional_features(account) helpers.update_optional_features(account)
@ -4979,21 +4974,28 @@ class RosterWindow:
if app.connections[account].pep_supported: if app.connections[account].pep_supported:
pep_submenu = Gtk.Menu() pep_submenu = Gtk.Menu()
pep_menuitem.set_submenu(pep_submenu) pep_menuitem.set_submenu(pep_submenu)
def add_item(label, opt_name, func):
item = Gtk.CheckMenuItem.new_with_label(label) item = Gtk.CheckMenuItem(_('Publish Tune'))
pep_submenu.append(item) pep_submenu.append(item)
if not dbus_support.supported: if not dbus_support.supported:
item.set_sensitive(False) item.set_sensitive(False)
else: else:
activ = app.config.get_per('accounts', account, activ = app.config.get_per('accounts', account,
opt_name) 'publish_tune')
item.set_active(activ) item.set_active(activ)
item.connect('toggled', func, account) item.connect('toggled', self.on_publish_tune_toggled,
account)
add_item(_('Publish Tune'), 'publish_tune', item = Gtk.CheckMenuItem(_('Publish Location'))
self.on_publish_tune_toggled) pep_submenu.append(item)
add_item(_('Publish Location'), 'publish_location', if not app.HAVE_GEOCLUE:
self.on_publish_location_toggled) item.set_sensitive(False)
else:
activ = app.config.get_per('accounts', account,
'publish_location')
item.set_active(activ)
item.connect('toggled', self.on_publish_location_toggled,
account)
pep_config = Gtk.MenuItem.new_with_label( pep_config = Gtk.MenuItem.new_with_label(
_('Configure Services…')) _('Configure Services…'))