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&#39;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 = &quot;&quot;<br>         self._ip_address_label.set_text(ip_address_text)<br> <br>+<br> class GsmPalette(Palette):<br>     __gtype_name__ = &#39;SugarGsmPalette&#39;<br>
 <br>@@ -227,36 +230,48 @@ class GsmPalette(Palette):<br>     def __init__(self):<br> <br>         Palette.__init__(self, label=_(&#39;Wireless modem&#39;))<br>-<br>         self._current_state = None<br>+        self._alert = False<br>
 <br>-        self._toggle_state_item = gtk.MenuItem(&#39;&#39;)<br>+        self._toggle_state_item = MenuItem(&#39;&#39;)<br>         self._toggle_state_item.connect(&#39;activate&#39;, 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=&#39;data-upload&#39;, 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=&#39;data-download&#39;, 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(&#39;&#39;)<br>+        self._error_accept_item.connect(&#39;activate&#39;, 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(&#39;...&#39;)<br>
             self.props.secondary_text = _(&#39;Please wait...&#39;)<br>-<br>+    <br>         elif self._current_state == _GSM_STATE_DISCONNECTED:<br>             self._toggle_state_item.get_child().set_label(_(&#39;Connect&#39;))<br>
-            self.props.secondary_text = _(&#39;Disconnected&#39;)<br>-<br>+            if not self._alert: <br>+                self.props.secondary_text = _(&#39;Disconnected&#39;)<br>+            icon = Icon(icon_name=&#39;dialog-ok&#39;, \<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(_(&#39;Cancel&#39;))<br>
             self.props.secondary_text = _(&#39;Connecting...&#39;)<br>+            icon = Icon(icon_name=&#39;dialog-cancel&#39;, \<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(_(&#39;Disconnect&#39;))<br>-            self.props.secondary_text = _(&#39;Connected&#39;)<br>
-            <br>-        elif self._current_state == _GSM_STATE_NEED_AUTH:<br>-            self._toggle_state_item.get_child().set_label(_(&#39;Sim requires Pin/Puk&#39;))<br>-            self.props.secondary_text = _(&#39;Authentication Error&#39;)<br>
+            self.update_connection_time()<br>+            icon = Icon(icon_name=&#39;media-eject&#39;, \<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(_(&#39;Connection Error&#39;), \<br>+                            self._get_error_by_nm_reason(reason))<br>
             <br>         else:<br>             raise ValueError(&#39;Invalid GSM state while updating label and &#39; \<br>                              &#39;text, %s&#39; % 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(&#39;&#39;)<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 = _(&#39;Connected for &#39; + \<br>+                                      connection_time.strftime(&#39;%H:%M:%S&#39;))<br>+        else:<br>+            self.props.secondary_text = _(&#39;Connected for &#39; \<br>
+                                          + &#39;00:00:00&#39;)<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(_(&quot;%d KB&quot;) % (out_KBytes))<br>+        self._data_label_down.set_text(_(&quot;%d KB&quot;) % (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 = _(&#39;The Pin/Puk configuration is not valid.&#39;)<br>+        elif reason in [network.NM_DEVICE_STATE_REASON_PPP_DISCONNECT, network.NM_DEVICE_STATE_REASON_PPP_FAILED]:<br>
+            message = _(&#39;Check the APN configuration.&#39;)<br>+        elif reason in [network.NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER]:<br>+            message = _(&#39;Check the tel number configuration.&#39;)<br>
+        elif reason in [network.NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT]:<br>+            message = _(&#39;Time out. Check the tel configuration&#39;)<br>+        else:<br>+            message = _(&#39;Unexpected error.&#39;)<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(&#39;gsm-disconnect&#39;)<br>
         elif self._current_state == _GSM_STATE_CONNECTED:<br>             self.emit(&#39;gsm-disconnect&#39;)<br>-        elif self._current_state == _GSM_STATE_NEED_AUTH:<br>-            self.emit(&#39;gsm-disconnect&#39;)<br>
         else:<br>             raise ValueError(&#39;Invalid GSM state while emitting signal, %s&#39; % \<br>                              str(self._current_state))<br>-<br>+            <br> <br> class WirelessDeviceView(ToolButton):<br>
 <br>@@ -747,6 +814,7 @@ class GsmDeviceView(TrayIcon):<br>                                       signal_name=&#39;PppStats&#39;,<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>                                         &#39;/&#39;,<br>                                         reply_handler=self.__connect_cb,<br>
                                         error_handler=self.__connect_error_cb)<br>+        else:<br>+            self._palette.add_alert(_(&#39;Connection Error&#39;), \<br>+                                    _(&#39;There is no gsm connection available&#39;))<br>
 <br>     def __connect_cb(self, active_connection):<br>         logging.debug(&#39;Connected successfully to gsm device, %s&#39;,<br>@@ -807,15 +878,15 @@ class GsmDeviceView(TrayIcon):<br> <br>     def __state_changed_cb(self, new_state, old_state, reason):<br>
         logging.debug(&#39;State: %s to %s, reason %s&#39;, 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[&#39;State&#39;]))<br>+        self._update_state(int(properties[&#39;State&#39;]), 0, 0)<br> <br>     def __current_state_check_error_cb(self, error):<br>
         raise RuntimeError(&#39;Error when checking gsm device state, %s&#39; % 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 = _(&quot;Data sent %d KB / received %d KB&quot;) % (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 = _(&quot;Connection time &quot;) + connection_time.strftime(&#39;%H : %M : %S&#39;)<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(&#39;Secrets requested for connection %s request_new=%s&#39;,<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(&#39;Error requesting the secrets via dialog&#39;)<br>-        else:<br>-            reply(self._secrets.get_dict())<br>-<br>-<br>+        if self._settings.connection.type is not &#39;gsm&#39;:<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(&#39;Error requesting the secrets via dialog&#39;)<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(&#39;The stored GSM secret has already been supplied &#39;)<br>+                    <br> class AccessPoint(gobject.GObject):<br>     __gsignals__ = {<br>         &#39;props-changed&#39;: (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>