Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSimon Schampijer <simon@schampijer.de>2010-09-22 10:40:38 (GMT)
committer Simon Schampijer <simon@schampijer.de>2010-09-22 10:40:38 (GMT)
commit824ac2a6a6dddf36c9f795cf0249eb5bebe60f54 (patch)
tree165a6a7519226c210d302225576bad26d3d599cf /src
parentf76678cbbbaa91a83575b59fdfd31abd74610fab (diff)
Add default Ad-hoc networks #9845
This patch adds three default Ad-hoc networks, for channel 1, 6 and 11. They are represented with designated icons in the neighborhood view. This will mimic the mesh behavior on devices where mesh hardware is not available and make the "under a tree"-scenario possible in those cases. If Sugar sees no "known" network when it starts, it does autoconnect to an Ad-hoc network.
Diffstat (limited to 'src')
-rw-r--r--src/jarabe/desktop/meshbox.py298
-rw-r--r--src/jarabe/model/Makefile.am1
-rw-r--r--src/jarabe/model/network.py40
3 files changed, 298 insertions, 41 deletions
diff --git a/src/jarabe/desktop/meshbox.py b/src/jarabe/desktop/meshbox.py
index a3965f7..764aa2e 100644
--- a/src/jarabe/desktop/meshbox.py
+++ b/src/jarabe/desktop/meshbox.py
@@ -1,6 +1,6 @@
# Copyright (C) 2006-2007 Red Hat, Inc.
# Copyright (C) 2009 Tomeu Vizoso, Simon Schampijer
-# Copyright (C) 2009 One Laptop per Child
+# Copyright (C) 2009-2010 One Laptop per Child
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -24,6 +24,7 @@ import dbus
import hippo
import gobject
import gtk
+import gconf
from sugar.graphics.icon import CanvasIcon, Icon
from sugar.graphics.xocolor import XoColor
@@ -54,6 +55,7 @@ from jarabe.model.network import WirelessSecurity
from jarabe.model.network import AccessPoint
from jarabe.model.network import OlpcMesh as OlpcMeshSettings
from jarabe.model.olpcmesh import OlpcMeshManager
+from jarabe.model.adhoc import get_adhoc_manager_instance
_NM_SERVICE = 'org.freedesktop.NetworkManager'
_NM_IFACE = 'org.freedesktop.NetworkManager'
@@ -89,11 +91,9 @@ class WirelessNetworkView(CanvasPulsingIcon):
self._device_state = None
self._color = None
- if self._mode == network.NM_802_11_MODE_ADHOC \
- and self._name_encodes_colors():
- encoded_color = self._name.split("#", 1)
- if len(encoded_color) == 2:
- self._color = xocolor.XoColor('#' + encoded_color[1])
+ if self._mode == network.NM_802_11_MODE_ADHOC and \
+ network.is_sugar_adhoc_network(self._name):
+ self._color = profile.get_color()
else:
sh = sha.new()
data = self._name + hex(self._flags)
@@ -137,11 +137,6 @@ class WirelessNetworkView(CanvasPulsingIcon):
path=self._device.object_path,
dbus_interface=_NM_WIRELESS_IFACE)
- def _name_encodes_colors(self):
- """Match #XXXXXX,#YYYYYY at the end of the network name"""
- return self._name[-7] == '#' and self._name[-8] == ',' \
- and self._name[-15] == '#'
-
def _create_palette(self):
icon_name = get_icon_state(_AP_ICON_NAME, self._strength)
self._palette_icon = Icon(icon_name=icon_name,
@@ -214,21 +209,32 @@ class WirelessNetworkView(CanvasPulsingIcon):
else:
state = network.DEVICE_STATE_UNKNOWN
- if state == network.DEVICE_STATE_ACTIVATED:
- connection = network.find_connection_by_ssid(self._name)
- if connection:
- if self._mode == network.NM_802_11_MODE_INFRA:
- connection.set_connected()
-
- icon_name = '%s-connected' % _AP_ICON_NAME
- else:
- icon_name = _AP_ICON_NAME
-
- icon_name = get_icon_state(icon_name, self._strength)
- if icon_name:
+ if self._mode == network.NM_802_11_MODE_ADHOC and \
+ network.is_sugar_adhoc_network(self._name):
+ channel = max([1] + [ap.channel for ap in
+ self._access_points.values()])
+ if state == network.DEVICE_STATE_ACTIVATED:
+ icon_name = 'network-adhoc-%s-connected' % channel
+ else:
+ icon_name = 'network-adhoc-%s' % channel
self.props.icon_name = icon_name
icon = self._palette.props.icon
icon.props.icon_name = icon_name
+ else:
+ if state == network.DEVICE_STATE_ACTIVATED:
+ connection = network.find_connection_by_ssid(self._name)
+ if connection:
+ if self._mode == network.NM_802_11_MODE_INFRA:
+ connection.set_connected()
+ icon_name = '%s-connected' % _AP_ICON_NAME
+ else:
+ icon_name = _AP_ICON_NAME
+
+ icon_name = get_icon_state(icon_name, self._strength)
+ if icon_name:
+ self.props.icon_name = icon_name
+ icon = self._palette.props.icon
+ icon.props.icon_name = icon_name
if state == network.DEVICE_STATE_PREPARE or \
state == network.DEVICE_STATE_CONFIG or \
@@ -260,12 +266,16 @@ class WirelessNetworkView(CanvasPulsingIcon):
self.props.base_color = self._color
def _update_badge(self):
- if network.find_connection_by_ssid(self._name) is not None:
- self.props.badge_name = "emblem-favorite"
- self._palette_icon.props.badge_name = "emblem-favorite"
- elif self._flags == network.NM_802_11_AP_FLAGS_PRIVACY:
- self.props.badge_name = "emblem-locked"
- self._palette_icon.props.badge_name = "emblem-locked"
+ if self._mode != network.NM_802_11_MODE_ADHOC:
+ if network.find_connection_by_ssid(self._name) is not None:
+ self.props.badge_name = "emblem-favorite"
+ self._palette_icon.props.badge_name = "emblem-favorite"
+ elif self._flags == network.NM_802_11_AP_FLAGS_PRIVACY:
+ self.props.badge_name = "emblem-locked"
+ self._palette_icon.props.badge_name = "emblem-locked"
+ else:
+ self.props.badge_name = None
+ self._palette_icon.props.badge_name = None
else:
self.props.badge_name = None
self._palette_icon.props.badge_name = None
@@ -469,6 +479,140 @@ class WirelessNetworkView(CanvasPulsingIcon):
dbus_interface=_NM_WIRELESS_IFACE)
+class SugarAdhocView(CanvasPulsingIcon):
+ """To mimic the mesh behavior on devices where mesh hardware is
+ not available we support the creation of an Ad-hoc network on
+ three channels 1, 6, 11. This is the class for an icon
+ representing a channel in the neighborhood view.
+
+ """
+
+ _ICON_NAME = 'network-adhoc-'
+ _NAME = 'Ad-hoc Network '
+
+ def __init__(self, channel):
+ CanvasPulsingIcon.__init__(self,
+ icon_name=self._ICON_NAME + str(channel),
+ size=style.STANDARD_ICON_SIZE, cache=True)
+ self._bus = dbus.SystemBus()
+ self._channel = channel
+ self._disconnect_item = None
+ self._connect_item = None
+ self._palette_icon = None
+ self._greyed_out = False
+
+ get_adhoc_manager_instance().connect('members-changed',
+ self.__members_changed_cb)
+ get_adhoc_manager_instance().connect('state-changed',
+ self.__state_changed_cb)
+
+ self.connect('button-release-event', self.__button_release_event_cb)
+
+ pulse_color = XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(),
+ style.COLOR_TRANSPARENT.get_svg()))
+ self.props.pulse_color = pulse_color
+ self._state_color = XoColor('%s,%s' % \
+ (profile.get_color().get_stroke_color(),
+ style.COLOR_TRANSPARENT.get_svg()))
+ self.props.base_color = self._state_color
+ self._palette = self._create_palette()
+ self.set_palette(self._palette)
+ self._palette_icon.props.xo_color = self._state_color
+
+ def _create_palette(self):
+ self._palette_icon = Icon( \
+ icon_name=self._ICON_NAME + str(self._channel),
+ icon_size=style.STANDARD_ICON_SIZE)
+
+ palette_ = palette.Palette(_("Ad-hoc Network %d") % self._channel,
+ icon=self._palette_icon)
+
+ self._connect_item = MenuItem(_('Connect'), 'dialog-ok')
+ self._connect_item.connect('activate', self.__connect_activate_cb)
+ palette_.menu.append(self._connect_item)
+
+ self._disconnect_item = MenuItem(_('Disconnect'), 'media-eject')
+ self._disconnect_item.connect('activate',
+ self.__disconnect_activate_cb)
+ palette_.menu.append(self._disconnect_item)
+
+ return palette_
+
+ def __button_release_event_cb(self, icon, event):
+ get_adhoc_manager_instance().activate_channel(self._channel)
+
+ def __connect_activate_cb(self, icon):
+ get_adhoc_manager_instance().activate_channel(self._channel)
+
+ def __disconnect_activate_cb(self, icon):
+ get_adhoc_manager_instance().deactivate_active_channel()
+
+ def __state_changed_cb(self, adhoc_manager, channel, device_state):
+ if self._channel == channel:
+ state = device_state
+ else:
+ state = network.DEVICE_STATE_UNKNOWN
+
+ if state == network.DEVICE_STATE_ACTIVATED:
+ icon_name = '%s-connected' % (self._ICON_NAME + str(self._channel))
+ else:
+ icon_name = self._ICON_NAME + str(self._channel)
+
+ self.props.base_color = self._state_color
+ self._palette_icon.props.xo_color = self._state_color
+
+ if icon_name is not None:
+ self.props.icon_name = icon_name
+ icon = self._palette.props.icon
+ icon.props.icon_name = icon_name
+
+ if state in [network.DEVICE_STATE_PREPARE,
+ network.DEVICE_STATE_CONFIG,
+ network.DEVICE_STATE_NEED_AUTH,
+ network.DEVICE_STATE_IP_CONFIG]:
+ if self._disconnect_item:
+ self._disconnect_item.show()
+ self._connect_item.hide()
+ self._palette.props.secondary_text = _('Connecting...')
+ self.props.pulsing = True
+ elif state == network.DEVICE_STATE_ACTIVATED:
+ if self._disconnect_item:
+ self._disconnect_item.show()
+ self._connect_item.hide()
+ self._palette.props.secondary_text = _('Connected')
+ self.props.pulsing = False
+ else:
+ if self._disconnect_item:
+ self._disconnect_item.hide()
+ self._connect_item.show()
+ self._palette.props.secondary_text = None
+ self.props.pulsing = False
+
+ def _update_color(self):
+ if self._greyed_out:
+ self.props.base_color = XoColor('#D5D5D5,#D5D5D5')
+ else:
+ self.props.base_color = self._state_color
+
+ def __members_changed_cb(self, adhoc_manager, channel, has_members):
+ if channel == self._channel:
+ if has_members == True:
+ self._state_color = profile.get_color()
+ self.props.base_color = self._state_color
+ self._palette_icon.props.xo_color = self._state_color
+ else:
+ color = '%s,%s' % (profile.get_color().get_stroke_color(),
+ style.COLOR_TRANSPARENT.get_svg())
+ self._state_color = XoColor(color)
+ self.props.base_color = self._state_color
+ self._palette_icon.props.xo_color = self._state_color
+
+ def set_filter(self, query):
+ name = self._NAME + str(self._channel)
+ self._greyed_out = name.lower().find(query) == -1
+ self._update_color()
+
+
class OlpcMeshView(CanvasPulsingIcon):
def __init__(self, mesh_mgr, channel):
CanvasPulsingIcon.__init__(self, icon_name=_OLPC_MESH_ICON_NAME,
@@ -797,13 +941,19 @@ class MeshToolbar(gtk.Toolbar):
return False
-class DeviceObserver(object):
- def __init__(self, box, device):
- self._box = box
+class DeviceObserver(gobject.GObject):
+ __gsignals__ = {
+ 'access-point-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'access-point-removed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
+ def __init__(self, device):
+ gobject.GObject.__init__(self)
self._bus = dbus.SystemBus()
- self._device = device
+ self.device = device
- wireless = dbus.Interface(self._device, _NM_WIRELESS_IFACE)
+ wireless = dbus.Interface(device, _NM_WIRELESS_IFACE)
wireless.GetAccessPoints(reply_handler=self._get_access_points_reply_cb,
error_handler=self._get_access_points_error_cb)
@@ -819,30 +969,33 @@ class DeviceObserver(object):
def _get_access_points_reply_cb(self, access_points_o):
for ap_o in access_points_o:
ap = self._bus.get_object(_NM_SERVICE, ap_o)
- self._box.add_access_point(self._device, ap)
+ self.emit('access-point-added', ap)
def _get_access_points_error_cb(self, err):
logging.error('Failed to get access points: %s', err)
def __access_point_added_cb(self, access_point_o):
ap = self._bus.get_object(_NM_SERVICE, access_point_o)
- self._box.add_access_point(self._device, ap)
+ self.emit('access-point-added', ap)
def __access_point_removed_cb(self, access_point_o):
- self._box.remove_access_point(access_point_o)
+ self.emit('access-point-removed', access_point_o)
def disconnect(self):
self._bus.remove_signal_receiver(self.__access_point_added_cb,
signal_name='AccessPointAdded',
- path=self._device.object_path,
+ path=self.device.object_path,
dbus_interface=_NM_WIRELESS_IFACE)
self._bus.remove_signal_receiver(self.__access_point_removed_cb,
signal_name='AccessPointRemoved',
- path=self._device.object_path,
+ path=self.device.object_path,
dbus_interface=_NM_WIRELESS_IFACE)
class NetworkManagerObserver(object):
+
+ _SHOW_ADHOC_GCONF_KEY = '/desktop/sugar/network/adhoc'
+
def __init__(self, box):
self._box = box
self._bus = dbus.SystemBus()
@@ -850,6 +1003,9 @@ class NetworkManagerObserver(object):
self._netmgr = None
self._olpc_mesh_device_o = None
+ client = gconf.client_get_default()
+ self._have_adhoc_networks = client.get_bool(self._SHOW_ADHOC_GCONF_KEY)
+
def listen(self):
try:
obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
@@ -867,6 +1023,9 @@ class NetworkManagerObserver(object):
self._bus.add_signal_receiver(self.__device_removed_cb,
signal_name='DeviceRemoved',
dbus_interface=_NM_IFACE)
+ self._bus.add_signal_receiver(self.__properties_changed_cb,
+ signal_name='PropertiesChanged',
+ dbus_interface=_NM_IFACE)
settings = network.get_settings()
if settings is not None:
@@ -909,7 +1068,13 @@ class NetworkManagerObserver(object):
device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType')
if device_type == network.DEVICE_TYPE_802_11_WIRELESS:
- self._devices[device_o] = DeviceObserver(self._box, device)
+ self._devices[device_o] = DeviceObserver(device)
+ self._devices[device_o].connect('access-point-added',
+ self.__ap_added_cb)
+ self._devices[device_o].connect('access-point-removed',
+ self.__ap_removed_cb)
+ if self._have_adhoc_networks:
+ self._box.add_adhoc_networks(device)
elif device_type == network.DEVICE_TYPE_802_11_OLPC_MESH:
self._olpc_mesh_device_o = device_o
self._box.enable_olpc_mesh(device)
@@ -925,11 +1090,29 @@ class NetworkManagerObserver(object):
observer = self._devices[device_o]
observer.disconnect()
del self._devices[device_o]
+ if self._have_adhoc_networks:
+ self._box.remove_adhoc_networks()
return
if self._olpc_mesh_device_o == device_o:
self._box.disable_olpc_mesh(device_o)
+ def __ap_added_cb(self, device_observer, access_point):
+ self._box.add_access_point(device_observer.device, access_point)
+
+ def __ap_removed_cb(self, device_observer, access_point_o):
+ self._box.remove_access_point(access_point_o)
+
+ def __properties_changed_cb(self, properties):
+ if 'WirelessHardwareEnabled' in properties:
+ if properties['WirelessHardwareEnabled']:
+ if not self._have_adhoc_networks:
+ self._box.remove_adhoc_networks()
+ elif properties['WirelessHardwareEnabled']:
+ for device in self._devices:
+ if self._have_adhoc_networks:
+ self._box.add_adhoc_networks(device)
+
class MeshBox(gtk.VBox):
__gtype_name__ = 'SugarMeshBox'
@@ -940,6 +1123,8 @@ class MeshBox(gtk.VBox):
gobject.GObject.__init__(self)
self.wireless_networks = {}
+ self._adhoc_manager = None
+ self._adhoc_networks = []
self._model = neighborhood.get_model()
self._buddies = {}
@@ -1097,6 +1282,15 @@ class MeshBox(gtk.VBox):
ap.disconnect()
return
+ if self._adhoc_manager is not None and \
+ network.is_sugar_adhoc_network(ap.name) and \
+ ap.mode == network.NM_802_11_MODE_ADHOC:
+ if old_hash is None: # new Ad-hoc network finished initializing
+ self._adhoc_manager.add_access_point(ap)
+ # we are called as well in other cases but we do not need to
+ # act here as we don't display signal strength for Ad-hoc networks
+ return
+
if old_hash is None: # new AP finished initializing
self._add_ap_to_network(ap)
return
@@ -1119,6 +1313,11 @@ class MeshBox(gtk.VBox):
ap.initialize()
def remove_access_point(self, ap_o):
+ if self._adhoc_manager is not None:
+ if self._adhoc_manager.is_sugar_adhoc_access_point(ap_o):
+ self._adhoc_manager.remove_access_point(ap_o)
+ return
+
# we don't keep an index of ap object path to network, but since
# we'll only ever have a handful of networks, just try them all...
for net in self.wireless_networks.values():
@@ -1135,6 +1334,25 @@ class MeshBox(gtk.VBox):
# it (e.g. olpc-mesh adhoc network)
logging.debug('Can not remove access point %s' % ap_o)
+ def add_adhoc_networks(self, device):
+ if self._adhoc_manager is None:
+ self._adhoc_manager = get_adhoc_manager_instance()
+ self._adhoc_manager.start_listening(device)
+ self._add_adhoc_network_icon(1)
+ self._add_adhoc_network_icon(6)
+ self._add_adhoc_network_icon(11)
+ self._adhoc_manager.autoconnect()
+
+ def remove_adhoc_networks(self):
+ for icon in self._adhoc_networks:
+ self._layout.remove(icon)
+ self._adhoc_networks = []
+
+ def _add_adhoc_network_icon(self, channel):
+ icon = SugarAdhocView(channel)
+ self._layout.add(icon)
+ self._adhoc_networks.append(icon)
+
def _add_olpc_mesh_icon(self, mesh_mgr, channel):
icon = OlpcMeshView(mesh_mgr, channel)
self._layout.add(icon)
diff --git a/src/jarabe/model/Makefile.am b/src/jarabe/model/Makefile.am
index 18d44da..1df2cde 100644
--- a/src/jarabe/model/Makefile.am
+++ b/src/jarabe/model/Makefile.am
@@ -1,5 +1,6 @@
sugardir = $(pythondir)/jarabe/model
sugar_PYTHON = \
+ adhoc.py \
__init__.py \
buddy.py \
bundleregistry.py \
diff --git a/src/jarabe/model/network.py b/src/jarabe/model/network.py
index 8af2591..f0297c9 100644
--- a/src/jarabe/model/network.py
+++ b/src/jarabe/model/network.py
@@ -1,6 +1,6 @@
# Copyright (C) 2008 Red Hat, Inc.
# Copyright (C) 2009 Tomeu Vizoso, Simon Schampijer
-# Copyright (C) 2009 One Laptop per Child
+# Copyright (C) 2009-2010 One Laptop per Child
# Copyright (C) 2009 Paraguay Educa, Martin Abente
#
# This program is free software; you can redistribute it and/or modify
@@ -100,6 +100,38 @@ GSM_PUK_PATH = '/desktop/sugar/network/gsm/puk'
_nm_settings = None
_conn_counter = 0
+def frequency_to_channel(frequency):
+ """Returns the channel matching a given radio channel frequency. If a
+ frequency is not in the dictionary channel 1 will be returned.
+
+ Keyword arguments:
+ frequency -- The radio channel frequency in MHz.
+
+ Return: Channel
+
+ """
+ ftoc = {2412: 1, 2417: 2, 2422: 3, 2427: 4,
+ 2432: 5, 2437: 6, 2442: 7, 2447: 8,
+ 2452: 9, 2457: 10, 2462: 11, 2467: 12,
+ 2472: 13}
+ if frequency not in ftoc:
+ logging.warning("The frequency %s can not be mapped to a channel, " \
+ "defaulting to channel 1.", frequency)
+ return 1
+ return ftoc[frequency]
+
+def is_sugar_adhoc_network(ssid):
+ """Checks whether an access point is a sugar Ad-hoc network.
+
+ Keyword arguments:
+ ssid -- Ssid of the access point.
+
+ Return: Boolean
+
+ """
+ return ssid.startswith('Ad-hoc Network')
+
+
class WirelessSecurity(object):
def __init__(self):
self.key_mgmt = None
@@ -127,6 +159,7 @@ class Wireless(object):
self.security = None
self.mode = None
self.band = None
+ self.channel = None
def get_dict(self):
wireless = {'ssid': self.ssid}
@@ -136,6 +169,8 @@ class Wireless(object):
wireless['mode'] = self.mode
if self.band:
wireless['band'] = self.band
+ if self.channel:
+ wireless['channel'] = self.channel
return wireless
class OlpcMesh(object):
@@ -509,6 +544,7 @@ class AccessPoint(gobject.GObject):
self.wpa_flags = 0
self.rsn_flags = 0
self.mode = 0
+ self.channel = 0
def initialize(self):
model_props = dbus.Interface(self.model, dbus.PROPERTIES_IFACE)
@@ -577,6 +613,8 @@ class AccessPoint(gobject.GObject):
self.rsn_flags = properties['RsnFlags']
if 'Mode' in properties:
self.mode = properties['Mode']
+ if 'Frequency' in properties:
+ self.channel = frequency_to_channel(properties['Frequency'])
self._initialized = True
self.emit('props-changed', old_hash)