diff options
author | Ajay Garg <ajay@activitycentral.com> | 2012-10-14 18:21:26 (GMT) |
---|---|---|
committer | Ajay Garg <ajay@activitycentral.com> | 2012-10-15 15:48:42 (GMT) |
commit | 9677e9fd273963ecd7be54022d40340c89c2a0c4 (patch) | |
tree | 70d93bcd60d4efa9839a0d1c7c22c1675ffc933e | |
parent | 81ada148b643f50d645a7ad650608430c1f494cf (diff) |
3G-Network sharing.
Signed-off-by: Ajay Garg <ajay@activitycentral.com>
-rw-r--r-- | extensions/deviceicon/network.py | 222 | ||||
-rw-r--r-- | src/jarabe/model/network.py | 8 |
2 files changed, 192 insertions, 38 deletions
diff --git a/extensions/deviceicon/network.py b/extensions/deviceicon/network.py index 79bc764..8ca9077 100644 --- a/extensions/deviceicon/network.py +++ b/extensions/deviceicon/network.py @@ -23,6 +23,8 @@ import logging import hashlib import socket import struct +import random +import re import datetime import time from gi.repository import Gtk @@ -30,6 +32,7 @@ import glib from gi.repository import GObject from gi.repository import GConf import dbus +import uuid from sugar3.graphics.icon import get_icon_state from sugar3.graphics import style @@ -55,6 +58,14 @@ _GSM_STATE_CONNECTING = 2 _GSM_STATE_CONNECTED = 3 _GSM_STATE_FAILED = 4 +_GSM_SHARING_PRIVATE = 0 +_GSM_SHARING_TRYING = 1 +_GSM_SHARING_NEIGHBORHOOD = 2 + +_GSM_SHARING_CHANNELS = [2,3,4,5,7,8,9,10,12,13] + +_wifi_device = None + class WirelessPalette(Palette): __gtype_name__ = 'SugarWirelessPalette' @@ -200,6 +211,8 @@ class GsmPalette(Palette): __gsignals__ = { 'gsm-connect': (GObject.SignalFlags.RUN_FIRST, None, ([])), 'gsm-disconnect': (GObject.SignalFlags.RUN_FIRST, None, ([])), + 'gsm-private': (GObject.SignalFlags.RUN_FIRST, None, ([])), + 'gsm-neighborhood': (GObject.SignalFlags.RUN_FIRST, None, ([])), } def __init__(self): @@ -208,6 +221,7 @@ class GsmPalette(Palette): self._current_state = None self._failed_connection = False + self._sharing_state = _GSM_SHARING_PRIVATE self.info_box = Gtk.VBox() @@ -216,6 +230,11 @@ class GsmPalette(Palette): self.info_box.pack_start(self._toggle_state_item, True, True, 0) self._toggle_state_item.show() + self._sharing_box = Gtk.VBox() + self.info_box.pack_start(self._sharing_box, True, True, 0) + self.__update_sharing_toggle_widget(_('Private (Click to share)'), 'zoom-home') + self._sharing_box.hide() + self.error_title_label = Gtk.Label(label="") self.error_title_label.set_alignment(0, 0.5) self.error_title_label.set_line_wrap(True) @@ -298,6 +317,9 @@ class GsmPalette(Palette): icon = Icon(icon_name='media-eject', \ icon_size=Gtk.IconSize.MENU) self._toggle_state_item.set_image(icon) + self.sharing_update_text() + self._sharing_toggle_item.show() + return elif self._current_state == _GSM_STATE_FAILED: message_error = self._get_error_by_nm_reason(reason) @@ -306,6 +328,8 @@ class GsmPalette(Palette): raise ValueError('Invalid GSM state while updating label and ' \ 'text, %s' % str(self._current_state)) + self._sharing_toggle_item.hide() + def __toggle_state_cb(self, menuitem): if self._current_state == _GSM_STATE_NOT_READY: pass @@ -366,6 +390,50 @@ class GsmPalette(Palette): message_tuple = (network.get_error_by_reason(reason), message) return message_tuple + def sharing_update_text(self): + if self._sharing_state == _GSM_SHARING_PRIVATE: + self.__update_sharing_toggle_widget(_('Private (Click to share)'), 'zoom-home') + + elif self._sharing_state == _GSM_SHARING_TRYING: + self.__update_sharing_toggle_widget(_('Please wait...'), 'zoom-home') + + elif self._sharing_state == _GSM_SHARING_NEIGHBORHOOD: + self.__update_sharing_toggle_widget(_('Neighborhood (Click to unshare)'), 'zoom-neighborhood') + + else: + raise ValueError('Invalid GSM sharing state while updating, %s' % \ + str(self._sharing_state)) + + def __update_sharing_toggle_widget(self, label, icon_name): + for child_widget in self._sharing_box.get_children(): + self._sharing_box.remove(child_widget) + + self._sharing_toggle_item = PaletteMenuItem('') + self._sharing_toggle_item.connect('activate', self.__sharing_toggle_cb) + self._sharing_toggle_item.set_label(label) + icon = Icon(icon_name=icon_name, icon_size=Gtk.IconSize.MENU) + self._sharing_toggle_item.set_image(icon) + icon.show() + self._sharing_box.pack_start(self._sharing_toggle_item, True, True, 0) + separator = PaletteMenuItemSeparator() + self._sharing_box.pack_start(separator, True, True, 0) + separator.show() + self._sharing_box.show_all() + + def __sharing_toggle_cb(self, menuitem): + if self._sharing_state == _GSM_SHARING_PRIVATE: + self.emit('gsm-neighborhood') + + elif self._sharing_state == _GSM_SHARING_TRYING: + pass + + elif self._sharing_state == _GSM_SHARING_NEIGHBORHOOD: + self.emit('gsm-private') + + else: + raise ValueError('Invalid GSM sharing state, %s' % \ + str(self._sharing_state)) + class WirelessDeviceView(ToolButton): @@ -527,17 +595,8 @@ class WirelessDeviceView(ToolButton): else: state = network.NM_DEVICE_STATE_UNKNOWN - if self._mode != network.NM_802_11_MODE_ADHOC and \ - network.is_sugar_adhoc_network(self._ssid) == False: - if state == network.NM_DEVICE_STATE_ACTIVATED: - icon_name = '%s-connected' % 'network-wireless' - else: - icon_name = 'network-wireless' - - icon_name = get_icon_state(icon_name, self._strength) - if icon_name: - self._icon.props.icon_name = icon_name - else: + if self._mode == network.NM_802_11_MODE_ADHOC and \ + network.is_sugar_adhoc_network(self._ssid): channel = network.frequency_to_channel(self._frequency) if state == network.NM_DEVICE_STATE_ACTIVATED: self._icon.props.icon_name = 'network-adhoc-%s-connected' \ @@ -729,8 +788,9 @@ class GsmDeviceView(TrayIcon): def __init__(self, device): self._connection_time_handler = None - self._connection_timestamp = 0 + self._shared_connection_path = None + self._target_dev_path = None client = GConf.Client.get_default() color = xocolor.XoColor(client.get_string('/desktop/sugar/user/color')) @@ -758,6 +818,8 @@ class GsmDeviceView(TrayIcon): palette.set_group_id('frame') palette.connect('gsm-connect', self.__gsm_connect_cb) palette.connect('gsm-disconnect', self.__gsm_disconnect_cb) + palette.connect('gsm-neighborhood', self.__gsm_start_sharing_cb) + palette.connect('gsm-private', self.__gsm_stop_sharing_cb) self._palette = palette @@ -775,42 +837,32 @@ class GsmDeviceView(TrayIcon): def __gsm_connect_cb(self, palette, data=None): connection = network.find_gsm_connection() if connection is not None: - connection.activate(self._device.object_path, - reply_handler=self.__connect_cb, - error_handler=self.__connect_error_cb) + network.activate_connection_by_path(connection.get_path(), + self._device.object_path, + reply_handler=self._connect_cb, + error_handler=self._connect_error_cb) else: self._palette.add_alert(_('No GSM connection available.'), \ _('Create a connection in the ' \ 'control panel.')) - def __connect_cb(self, active_connection): + def _connect_cb(self, active_connection_path): + self._base_gsm_connection_path = active_connection_path logging.debug('Connected successfully to gsm device, %s', - active_connection) + active_connection_path) - def __connect_error_cb(self, error): + def _connect_error_cb(self, error): raise RuntimeError('Error when connecting to gsm device, %s' % error) def __gsm_disconnect_cb(self, palette, data=None): - obj = self._bus.get_object(network.NM_SERVICE, network.NM_PATH) - netmgr = dbus.Interface(obj, network.NM_IFACE) - netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE) - active_connections_o = netmgr_props.Get(network.NM_IFACE, 'ActiveConnections') + network.get_manager().DeactivateConnection(self._base_gsm_connection_path, + reply_handler=self._disconnect_cb, + error_handler=self._disconnect_error_cb) - for conn_o in active_connections_o: - obj = self._bus.get_object(network.NM_IFACE, conn_o) - props = dbus.Interface(obj, dbus.PROPERTIES_IFACE) - devices = props.Get(network.NM_ACTIVE_CONN_IFACE, 'Devices') - if self._device.object_path in devices: - netmgr.DeactivateConnection( - conn_o, - reply_handler=self.__disconnect_cb, - error_handler=self.__disconnect_error_cb) - break - - def __disconnect_cb(self): + def _disconnect_cb(self): logging.debug('Disconnected successfully gsm device') - def __disconnect_error_cb(self, error): + def _disconnect_error_cb(self, error): raise RuntimeError('Error when disconnecting gsm device, %s' % error) def __state_changed_cb(self, new_state, old_state, reason): @@ -831,6 +883,10 @@ class GsmDeviceView(TrayIcon): gsm_state = _GSM_STATE_CONNECTED connection = network.find_gsm_connection() if connection is not None: + # Introspect the settings's keys once; else sometimes + # the key 'timestamp' gets missed. + connection.get_settings('connection').keys() + self._connection_timestamp = time.time() - \ connection.get_settings('connection')['timestamp'] self._connection_time_handler = GObject.timeout_add_seconds( \ @@ -879,6 +935,95 @@ class GsmDeviceView(TrayIcon): self._palette.update_connection_time(connection_time) return True + def __gsm_start_sharing_cb(self, palette): + if self._palette._sharing_state == _GSM_SHARING_PRIVATE: + logging.debug('GSM will start sharing now') + self._palette._sharing_state = _GSM_SHARING_TRYING + self._palette.sharing_update_text() + + self._target_device = _wifi_device + self._target_device_path = self._target_device.object_path + + client = GConf.Client.get_default() + nick = client.get_string('/desktop/sugar/user/nick') + nick = re.sub('\W', '', nick) + + name_format = '%s network' + format_length = len(name_format) - len('%s') + nick_length = 31 - format_length + name = name_format % nick[:nick_length] + + connection = network.find_connection_by_ssid(name) + if connection == None: + settings = network.Settings() + settings.connection.id = name + settings.connection.uuid = str(uuid.uuid4()) + settings.connection.type = '802-11-wireless' + settings.wireless.ssid = dbus.ByteArray(name) + settings.wireless.mode = 'adhoc' + settings.wireless.band = 'bg' + chosen_channel = random.randrange(len(_GSM_SHARING_CHANNELS)) + settings.wireless.channel = _GSM_SHARING_CHANNELS[chosen_channel] + settings.ip4_config = network.IP4Config() + settings.ip4_config.method = 'shared' + network.add_and_activate_connection(self._target_device, + settings, + '/', + self._gsm_sharing_ok_cb_for_add_and_activate, + self._gsm_sharing_error_cb) + else: + network.activate_connection_by_path(connection.get_path(), + self._target_device, + self._gsm_sharing_ok_cb, + self._gsm_sharing_error_cb) + + def _gsm_sharing_ok_cb_for_add_and_activate(self, + new_connection_path, + active_connection_path): + self._gsm_sharing_ok_cb(active_connection_path) + + def _gsm_sharing_ok_cb(self, connection_path): + logging.debug('GSM sharing is enabled') + self._shared_connection_path = connection_path + self._bus.add_signal_receiver(self._gsm_sharing_changed_cb, + signal_name='StateChanged', + path=self._target_device_path, + dbus_interface=network.NM_DEVICE_IFACE) + self._palette._sharing_state = _GSM_SHARING_NEIGHBORHOOD + self._palette.sharing_update_text() + + def _gsm_sharing_changed_cb(self, new_state, old_state, reason): + if new_state == network.NM_DEVICE_STATE_DISCONNECTED: + self._gsm_sharing_reset() + + def _gsm_sharing_reset(self): + logging.debug('GSM sharing is disabled') + if self._target_dev_path != None: + self._bus.remove_signal_receiver(self._gsm_sharing_changed_cb, + signal_name='StateChanged', + path=self._target_dev_path, + dbus_interface=network.NM_DEVICE_IFACE) + self._shared_connection_path = None + self._target_dev_path = None + self._palette._sharing_state = _GSM_SHARING_PRIVATE + self._palette.sharing_update_text() + + def _gsm_sharing_error_cb(self, error): + logging.debug('GSM sharing could not start: %s' % str(error)) + self._gsm_sharing_reset() + + def __gsm_stop_sharing_cb(self, palette): + logging.debug('GSM will stop sharing now') + network.get_manager().DeactivateConnection(self._shared_connection_path, + reply_handler=self._gsm_stop_sharing_ok_cb, + error_handler=self._gsm_stop_sharing_error_cb) + + def _gsm_stop_sharing_ok_cb(self): + self._gsm_sharing_reset() + + def _gsm_stop_sharing_error_cb(self): + logging.debug('GSM sharing could not stop') + class WirelessDeviceObserver(object): def __init__(self, device, tray): @@ -1056,6 +1201,8 @@ class NetworkManagerObserver(object): device = WiredDeviceObserver(nm_device, self._tray) self._devices[device_op] = device elif device_type == network.NM_DEVICE_TYPE_WIFI: + global _wifi_device + _wifi_device = nm_device device = WirelessDeviceObserver(nm_device, self._tray) self._devices[device_op] = device elif device_type == network.NM_DEVICE_TYPE_OLPC_MESH: @@ -1075,5 +1222,10 @@ class NetworkManagerObserver(object): del self._devices[device_op] +def get_wifi_device(): + global _wifi_device + return _wifi_device + + def setup(tray): device_observer = NetworkManagerObserver(tray) diff --git a/src/jarabe/model/network.py b/src/jarabe/model/network.py index fa7acba..c60f6af 100644 --- a/src/jarabe/model/network.py +++ b/src/jarabe/model/network.py @@ -910,12 +910,14 @@ def activate_connection_by_path(connection, device_o, error_handler=error_handler) -def add_and_activate_connection(device_o, settings, specific_object): +def add_and_activate_connection(device_o, settings, specific_object, + reply_handler=_add_and_activate_reply_cb, + error_handler=_add_and_activate_error_cb): manager = get_manager() manager.AddAndActivateConnection(settings.get_dict(), device_o, specific_object, - reply_handler=_add_and_activate_reply_cb, - error_handler=_add_and_activate_error_cb) + reply_handler=reply_handler, + error_handler=error_handler) def _migrate_old_wifi_connections(): |