I have this ticket pending, could you give your feedback? Thanks!!!<br><br><a href="http://bugs.sugarlabs.org/ticket/1759">http://bugs.sugarlabs.org/ticket/1759</a><br>
<br>This patch improves the feature 3G Support (added in 0.88).<br>
Includes:<br>
Show the connection errors<br>
Apply Eben's Mockup: <a class="ext-link" href="http://wiki.sugarlabs.org/go/File:3G_device.png"><span class="icon"> </span>http://wiki.sugarlabs.org/go/File:3G_device.png</a> <br><br><br>---<br> extensions/deviceicon/network.py | 183 ++++++++++++++++++++++++++------------<br>
src/jarabe/model/network.py | 34 +++++---<br> 2 files changed, 148 insertions(+), 69 deletions(-)<br><br>diff --git a/extensions/deviceicon/network.py b/extensions/deviceicon/network.py<br>index 94a4293..995446c 100644<br>
--- a/extensions/deviceicon/network.py<br>+++ b/extensions/deviceicon/network.py<br>@@ -39,6 +39,8 @@ from sugar.graphics.tray import TrayIcon<br> from sugar.graphics import xocolor<br> from sugar.util import unique_id<br>
from sugar import profile<br>+from sugar.graphics.icon import Icon<br>+from sugar.graphics.menuitem import MenuItem<br> <br> from jarabe.model import network<br> from jarabe.model.network import Settings<br>@@ -63,7 +65,7 @@ _GSM_STATE_NOT_READY = 0<br>
_GSM_STATE_DISCONNECTED = 1<br> _GSM_STATE_CONNECTING = 2<br> _GSM_STATE_CONNECTED = 3<br>-_GSM_STATE_NEED_AUTH = 4<br>+_GSM_STATE_FAILED = 4<br> <br> def frequency_to_channel(frequency):<br> ftoc = { 2412: 1, 2417: 2, 2422: 3, 2427: 4,<br>
@@ -214,6 +216,7 @@ class WiredPalette(Palette):<br> ip_address_text = ""<br> self._ip_address_label.set_text(ip_address_text)<br> <br>+<br> class GsmPalette(Palette):<br> __gtype_name__ = 'SugarGsmPalette'<br>
<br>@@ -227,36 +230,48 @@ class GsmPalette(Palette):<br> def __init__(self):<br> <br> Palette.__init__(self, label=_('Wireless modem'))<br>-<br> self._current_state = None<br>+ self._alert = False<br>
<br>- self._toggle_state_item = gtk.MenuItem('')<br>+ self._toggle_state_item = MenuItem('')<br> self._toggle_state_item.connect('activate', self.__toggle_state_cb)<br> self.menu.append(self._toggle_state_item)<br>
self._toggle_state_item.show()<br> <br>- self.set_state(_GSM_STATE_NOT_READY)<br>-<br> self.info_box = gtk.VBox()<br>-<br>- self.data_label = gtk.Label()<br>- self.data_label.props.xalign = 0.0<br>
- label_alignment = self._add_widget_with_padding(self.data_label)<br>- self.info_box.pack_start(label_alignment)<br>- self.data_label.show()<br>+ self.connection_info_box = gtk.HBox() <br>+<br>
+ icon = Icon(icon_name='data-upload', icon_size=gtk.ICON_SIZE_MENU)<br>+ self.connection_info_box.pack_start(icon)<br>+ icon.show()<br>+ self._data_label_up = gtk.Label()<br>+ self._data_label_up.props.xalign = 0.0<br>
+ label_alignment = self._add_widget_with_padding(self._data_label_up) <br>+ self.connection_info_box.pack_start(label_alignment)<br>+ self._data_label_up.show()<br> label_alignment.show()<br>
<br>- self.connection_time_label = gtk.Label()<br>- self.connection_time_label.props.xalign = 0.0<br>- label_alignment = self._add_widget_with_padding( \<br>- self.connection_time_label)<br>
- self.info_box.pack_start(label_alignment)<br>- self.connection_time_label.show()<br>+ icon = Icon(icon_name='data-download', icon_size=gtk.ICON_SIZE_MENU)<br>+ self.connection_info_box.pack_start(icon)<br>
+ icon.show()<br>+ self._data_label_down = gtk.Label()<br>+ self._data_label_down.props.xalign = 0.0<br>+ label_alignment = self._add_widget_with_padding(self._data_label_down) <br>+ self.connection_info_box.pack_start(label_alignment)<br>
+ self._data_label_down.show()<br> label_alignment.show()<br>+ <br>+ self.info_box.pack_start(self.connection_info_box)<br> <br>+ self._error_accept_item = MenuItem('')<br>+ self._error_accept_item.connect('activate', self.__error_accept_cb)<br>
+ self.menu.append(self._error_accept_item)<br>+ <br> self.info_box.show()<br> self.set_content(self.info_box)<br> <br>+ self.set_state(_GSM_STATE_NOT_READY)<br>+<br> def _add_widget_with_padding(self, child, xalign=0, yalign=0.5):<br>
alignment = gtk.Alignment(xalign=xalign, yalign=yalign,<br> xscale=1, yscale=0.33)<br>@@ -267,35 +282,89 @@ class GsmPalette(Palette):<br> alignment.add(child)<br> return alignment<br>
<br>- def set_state(self, state):<br>+ def set_state(self, state, reason=0):<br> self._current_state = state<br>- self._update_label_and_text()<br>+ self._update_label_and_text(reason)<br> <br>
- def _update_label_and_text(self):<br>+ def _update_label_and_text(self, reason=0):<br>+ <br> if self._current_state == _GSM_STATE_NOT_READY:<br> self._toggle_state_item.get_child().set_label('...')<br>
self.props.secondary_text = _('Please wait...')<br>-<br>+ <br> elif self._current_state == _GSM_STATE_DISCONNECTED:<br> self._toggle_state_item.get_child().set_label(_('Connect'))<br>
- self.props.secondary_text = _('Disconnected')<br>-<br>+ if not self._alert: <br>+ self.props.secondary_text = _('Disconnected')<br>+ icon = Icon(icon_name='dialog-ok', \<br>
+ icon_size=gtk.ICON_SIZE_MENU)<br>+ self._toggle_state_item.set_image(icon)<br>+ <br> elif self._current_state == _GSM_STATE_CONNECTING:<br> self._toggle_state_item.get_child().set_label(_('Cancel'))<br>
self.props.secondary_text = _('Connecting...')<br>+ icon = Icon(icon_name='dialog-cancel', \<br>+ icon_size=gtk.ICON_SIZE_MENU)<br>+ self._toggle_state_item.set_image(icon) <br>
<br> elif self._current_state == _GSM_STATE_CONNECTED:<br> self._toggle_state_item.get_child().set_label(_('Disconnect'))<br>- self.props.secondary_text = _('Connected')<br>
- <br>- elif self._current_state == _GSM_STATE_NEED_AUTH:<br>- self._toggle_state_item.get_child().set_label(_('Sim requires Pin/Puk'))<br>- self.props.secondary_text = _('Authentication Error')<br>
+ self.update_connection_time()<br>+ icon = Icon(icon_name='media-eject', \<br>+ icon_size=gtk.ICON_SIZE_MENU)<br>+ self._toggle_state_item.set_image(icon)<br>
+ <br>+ elif self._current_state == _GSM_STATE_FAILED:<br>+ self.add_alert(_('Connection Error'), \<br>+ self._get_error_by_nm_reason(reason))<br>
<br> else:<br> raise ValueError('Invalid GSM state while updating label and ' \<br> 'text, %s' % str(self._current_state))<br>-<br>+ <br>+ def add_alert(self, title, message):<br>
+ self._alert = True<br>+ self.props.secondary_text = title<br>+ self._error_accept_item.get_child().set_label(message)<br>+ self._error_accept_item.show()<br>+ self._toggle_state_item.set_sensitive(False)<br>
+ <br>+ <br>+ def __error_accept_cb(self, alert):<br>+ self._alert = False<br>+ self._update_label_and_text()<br>+ self._error_accept_item.get_child().set_label('')<br>+ self._error_accept_item.hide()<br>
+ self._toggle_state_item.set_sensitive(True)<br>+ self._full_request = [0, 0]<br>+ <br>+ def update_connection_time(self, connection_time=None):<br>+ if (connection_time is not None):<br>
+ self.props.secondary_text = _('Connected for ' + \<br>+ connection_time.strftime('%H:%M:%S'))<br>+ else:<br>+ self.props.secondary_text = _('Connected for ' \<br>
+ + '00:00:00')<br>+ <br>+ def update_stats(self, in_bytes, out_bytes):<br>+ in_KBytes = in_bytes / 1024<br>+ out_KBytes = out_bytes / 1024<br>
+ self._data_label_up.set_text(_("%d KB") % (out_KBytes))<br>+ self._data_label_down.set_text(_("%d KB") % (in_KBytes))<br>+ <br>+ def _get_error_by_nm_reason(self, reason):<br>
+ if reason in [network.NM_DEVICE_STATE_REASON_NO_SECRETS, network.NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED]:<br>+ message = _('The Pin/Puk configuration is not valid.')<br>+ elif reason in [network.NM_DEVICE_STATE_REASON_PPP_DISCONNECT, network.NM_DEVICE_STATE_REASON_PPP_FAILED]:<br>
+ message = _('Check the APN configuration.')<br>+ elif reason in [network.NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER]:<br>+ message = _('Check the tel number configuration.')<br>
+ elif reason in [network.NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT]:<br>+ message = _('Time out. Check the tel configuration')<br>+ else:<br>+ message = _('Unexpected error.')<br>
+ return message<br>+ <br> def __toggle_state_cb(self, menuitem):<br> if self._current_state == _GSM_STATE_NOT_READY:<br> pass<br>@@ -305,12 +374,10 @@ class GsmPalette(Palette):<br> self.emit('gsm-disconnect')<br>
elif self._current_state == _GSM_STATE_CONNECTED:<br> self.emit('gsm-disconnect')<br>- elif self._current_state == _GSM_STATE_NEED_AUTH:<br>- self.emit('gsm-disconnect')<br>
else:<br> raise ValueError('Invalid GSM state while emitting signal, %s' % \<br> str(self._current_state))<br>-<br>+ <br> <br> class WirelessDeviceView(ToolButton):<br>
<br>@@ -747,6 +814,7 @@ class GsmDeviceView(TrayIcon):<br> signal_name='PppStats',<br> path=self._device.object_path,<br> dbus_interface=_NM_SERIAL_IFACE)<br>
+ <br> def create_palette(self):<br> palette = GsmPalette()<br> <br>@@ -774,6 +842,9 @@ class GsmDeviceView(TrayIcon):<br> '/',<br> reply_handler=self.__connect_cb,<br>
error_handler=self.__connect_error_cb)<br>+ else:<br>+ self._palette.add_alert(_('Connection Error'), \<br>+ _('There is no gsm connection available'))<br>
<br> def __connect_cb(self, active_connection):<br> logging.debug('Connected successfully to gsm device, %s',<br>@@ -807,15 +878,15 @@ class GsmDeviceView(TrayIcon):<br> <br> def __state_changed_cb(self, new_state, old_state, reason):<br>
logging.debug('State: %s to %s, reason %s', old_state, new_state, reason)<br>- self._update_state(int(new_state))<br>+ self._update_state(int(new_state), int(old_state), int(reason))<br> <br>
def __current_state_check_cb(self, properties):<br>- self._update_state(int(properties['State']))<br>+ self._update_state(int(properties['State']), 0, 0)<br> <br> def __current_state_check_error_cb(self, error):<br>
raise RuntimeError('Error when checking gsm device state, %s' % error)<br> <br>- def _update_state(self, state):<br>+ def _update_state(self, state, old_state, reason):<br> gsm_state = None<br>
<br> if state is network.DEVICE_STATE_ACTIVATED:<br>@@ -823,20 +894,22 @@ class GsmDeviceView(TrayIcon):<br> connection = network.find_gsm_connection()<br> if connection is not None:<br> connection.set_connected()<br>
- self._connection_timestamp = time.time() - \<br>+ self._connection_timestamp = time.time() - \<br> connection.get_settings().connection.timestamp<br> self._connection_time_handler = gobject.timeout_add_seconds( \<br>
1, self.__connection_timecount_cb)<br>- self._update_stats(0, 0)<br>- self._update_connection_time() <br>- self._palette.info_box.show() <br>
+ self._palette.update_connection_time() <br>+ self._palette.update_stats(0, 0)<br>+ if self._palette is not None: <br>+ self._palette.connection_info_box.show() <br>
<br> elif state is network.DEVICE_STATE_DISCONNECTED:<br> gsm_state = _GSM_STATE_DISCONNECTED<br> self._connection_timestamp = 0<br> if self._connection_time_handler is not None:<br>
gobject.source_remove(self._connection_time_handler)<br>- self._palette.info_box.hide() <br>+ if self._palette is not None:<br>+ self._palette.connection_info_box.hide() <br>
<br> elif state in [network.DEVICE_STATE_UNMANAGED,<br> network.DEVICE_STATE_UNAVAILABLE,<br>@@ -845,14 +918,15 @@ class GsmDeviceView(TrayIcon):<br> <br> elif state in [network.DEVICE_STATE_PREPARE,<br>
network.DEVICE_STATE_CONFIG,<br>- network.DEVICE_STATE_IP_CONFIG]:<br>+ network.DEVICE_STATE_IP_CONFIG,<br>+ network.DEVICE_STATE_NEED_AUTH]:<br>
gsm_state = _GSM_STATE_CONNECTING<br>- <br>- elif state in [network.DEVICE_STATE_NEED_AUTH]:<br>- gsm_state = _GSM_STATE_NEED_AUTH<br>+<br>+ elif state == network.DEVICE_STATE_FAILED:<br>
+ gsm_state = _GSM_STATE_FAILED<br> <br> if self._palette is not None:<br>- self._palette.set_state(gsm_state)<br>+ self._palette.set_state(gsm_state, reason)<br> <br> def disconnect(self):<br>
self._bus.remove_signal_receiver(self.__state_changed_cb,<br>@@ -861,25 +935,17 @@ class GsmDeviceView(TrayIcon):<br> dbus_interface=_NM_DEVICE_IFACE)<br> <br> def __ppp_stats_changed_cb(self, in_bytes, out_bytes):<br>
- self._update_stats(in_bytes, out_bytes)<br>-<br>- def _update_stats(self, in_bytes, out_bytes):<br>- in_KBytes = in_bytes / 1024<br>- out_KBytes = out_bytes / 1024<br>- text = _("Data sent %d KB / received %d KB") % (out_KBytes, in_KBytes)<br>
- self._palette.data_label.set_text(text)<br>+ self._palette.update_stats(in_bytes, out_bytes)<br> <br> def __connection_timecount_cb(self):<br> self._connection_timestamp = self._connection_timestamp + 1<br>
- self._update_connection_time()<br>+ connection_time = \<br>+ datetime.datetime.fromtimestamp(self._connection_timestamp)<br>+ self._palette.update_connection_time(connection_time)<br> return True<br>
<br>- def _update_connection_time(self):<br>- connection_time = datetime.datetime.fromtimestamp( \<br>- self._connection_timestamp)<br>- text = _("Connection time ") + connection_time.strftime('%H : %M : %S')<br>
- self._palette.connection_time_label.set_text(text)<br> <br>+ <br> class WirelessDeviceObserver(object):<br> def __init__(self, device, tray, device_type):<br> self._device = device<br>@@ -950,6 +1016,7 @@ class WiredDeviceObserver(object):<br>
del self._device_view<br> self._device_view = None<br> <br>+<br> class GsmDeviceObserver(object):<br> def __init__(self, device, tray):<br> self._device = device<br>diff --git a/src/jarabe/model/network.py b/src/jarabe/model/network.py<br>
index 3a949da..579ed8d 100644<br>--- a/src/jarabe/model/network.py<br>+++ b/src/jarabe/model/network.py<br>@@ -54,6 +54,13 @@ NM_ACTIVE_CONNECTION_STATE_UNKNOWN = 0<br> NM_ACTIVE_CONNECTION_STATE_ACTIVATING = 1<br> NM_ACTIVE_CONNECTION_STATE_ACTIVATED = 2<br>
<br>+NM_DEVICE_STATE_REASON_NO_SECRETS = 7<br>+NM_DEVICE_STATE_REASON_PPP_DISCONNECT = 13<br>+NM_DEVICE_STATE_REASON_PPP_FAILED = 14<br>+NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER = 25<br>+NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT = 26<br>
+NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED = 34<br>+<br> NM_802_11_AP_FLAGS_NONE = 0x00000000<br> NM_802_11_AP_FLAGS_PRIVACY = 0x00000001<br> <br>@@ -444,17 +451,22 @@ class NMSettingsConnection(dbus.service.Object):<br>
def GetSecrets(self, setting_name, hints, request_new, reply, error):<br> logging.debug('Secrets requested for connection %s request_new=%s',<br> self.path, request_new)<br>- if request_new or self._secrets is None:<br>
- # request_new is for example the case when the pw on the AP changes<br>- response = SecretsResponse(self, reply, error)<br>- try:<br>- self.secrets_request.send(self, response=response)<br>
- except Exception:<br>- logging.exception('Error requesting the secrets via dialog')<br>- else:<br>- reply(self._secrets.get_dict())<br>-<br>-<br>+ if self._settings.connection.type is not 'gsm':<br>
+ if request_new or self._secrets is None:<br>+ # request_new is for example the case when the pw on the AP changes<br>+ response = SecretsResponse(self, reply, error)<br>
+ try:<br>+ self.secrets_request.send(self, response=response)<br>+ except Exception:<br>+ logging.exception('Error requesting the secrets via dialog')<br>
+ else:<br>+ reply(self._secrets.get_dict())<br>+ else: <br>+ if not request_new:<br>+ reply(self._secrets.get_dict())<br>+ else:<br>
+ raise Exception('The stored GSM secret has already been supplied ')<br>+ <br> class AccessPoint(gobject.GObject):<br> __gsignals__ = {<br> 'props-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,<br>
-- <br>1.6.2.5<br><br clear="all"><br>-- <br>Ing. Daniel Castelo<br>Plan Ceibal - Área Técnica<br>Avda. Italia 6201<br>Montevideo - Uruguay.<br>Tel.: 601.57.73 Interno 2228<br>E-mail : <a href="mailto:dcastelo@plan.ceibal.edu.uy">dcastelo@plan.ceibal.edu.uy</a><br>