Implement full USSD support.
authorGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Tue, 21 Aug 2012 09:16:08 +0000 (06:16 -0300)
committerGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Tue, 21 Aug 2012 09:16:08 +0000 (06:16 -0300)
This commit covers network and user originated USSD communication,
with support to response or just informative messages.

Makefile.am
dialer/gui.c
dialer/keypad.c
dialer/ussd.c [new file with mode: 0644]
dialer/ussd.h [new file with mode: 0644]

index 6c41e32..4316c7e 100644 (file)
@@ -40,6 +40,8 @@ dialer_dialer_SOURCES = \
        dialer/history.h \
        dialer/callscreen.c \
        dialer/callscreen.h \
+       dialer/ussd.c \
+       dialer/ussd.h \
        dialer/util.c \
        dialer/util.h
 
index 9f78262..d899a1b 100644 (file)
@@ -8,6 +8,7 @@
 #include "keypad.h"
 #include "history.h"
 #include "callscreen.h"
+#include "ussd.h"
 
 static Evas_Object *win = NULL;
 static Evas_Object *main_layout = NULL;
@@ -19,6 +20,7 @@ static Evas_Object *flip = NULL;
 static char def_theme[PATH_MAX] = "";
 
 static OFono_Callback_List_Modem_Node *callback_node_modem_changed = NULL;
+static OFono_Callback_List_USSD_Notify_Node *callback_node_ussd_notify = NULL;
 
 /* XXX elm_flip should just do the right thing, but it does not */
 static Eina_Bool in_call = EINA_FALSE;
@@ -487,6 +489,13 @@ static void _ofono_changed(void *data __UNUSED__)
        elm_object_part_text_set(main_layout, "elm.text.voicemail", buf);
 }
 
+static void _ofono_ussd_notify(void *data __UNUSED__, Eina_Bool needs_reply,
+                               const char *message)
+{
+       DBG("needs_reply=%d, message=%s", needs_reply, message);
+       ussd_start(message);
+}
+
 Eina_Bool gui_init(const char *theme)
 {
        Evas_Object *lay, *obj;
@@ -568,6 +577,8 @@ Eina_Bool gui_init(const char *theme)
 
        callback_node_modem_changed =
                ofono_modem_changed_cb_add(_ofono_changed, NULL);
+       callback_node_ussd_notify =
+               ofono_ussd_notify_cb_add(_ofono_ussd_notify, NULL);
 
        /* TODO: make it match better with Tizen: icon and other properties */
        obj = elm_layout_edje_get(lay);
index e9265fc..f4de578 100644 (file)
@@ -6,6 +6,7 @@
 #include "log.h"
 #include "gui.h"
 #include "ofono.h"
+#include "ussd.h"
 #include "util.h"
 
 /* timeout before a popup is show for supplementary services.  It is
@@ -306,9 +307,11 @@ static void _ss_initiate_reply(void *data, OFono_Error err, const char *str)
                gui_simple_popup_button_dismiss_set(ctx->ss_popup);
                evas_object_show(ctx->ss_popup);
        } else {
-               gui_simple_popup_message_set(ctx->ss_popup, str);
-               gui_simple_popup_button_dismiss_set(ctx->ss_popup);
-               evas_object_show(ctx->ss_popup);
+               evas_object_del(ctx->ss_popup);
+               eina_strbuf_reset(ctx->number);
+               _number_display(ctx);
+
+               ussd_start(str);
        }
 }
 
diff --git a/dialer/ussd.c b/dialer/ussd.c
new file mode 100644 (file)
index 0000000..c7e7696
--- /dev/null
@@ -0,0 +1,164 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <Elementary.h>
+
+#include "log.h"
+#include "gui.h"
+#include "ofono.h"
+
+typedef struct _USSD
+{
+       Evas_Object *popup;
+       OFono_Pending *pending;
+       OFono_USSD_State state;
+       const char *message;
+       OFono_Callback_List_Modem_Node *cb_changed;
+} USSD;
+
+static void _ussd_respond_reply(void *data, OFono_Error err, const char *str)
+{
+       USSD *ctx = data;
+
+       DBG("ctx=%p, e=%d, str=%s, popup=%p", ctx, err, str, ctx->popup);
+
+       ctx->pending = NULL;
+
+       /* no popup? then it was canceled */
+       if (!ctx->popup)
+               return;
+
+       if (err == OFONO_ERROR_NONE) {
+               eina_stringshare_replace(&(ctx->message), str);
+               gui_simple_popup_message_set(ctx->popup, ctx->message);
+       } else if (err == OFONO_ERROR_OFFLINE) {
+               gui_simple_popup_title_set(ctx->popup, "Offline");
+               gui_simple_popup_message_set(ctx->popup, "System is Offline");
+               gui_simple_popup_button_dismiss_set(ctx->popup);
+       } else {
+               char buf[256];
+
+               if (ctx->state == OFONO_USSD_STATE_USER_RESPONSE)
+                       snprintf(buf, sizeof(buf),
+                                       "Could not complete.<br>Error #%d.<br>"
+                                       "Try again:<br><br>%s",
+                                       err, ctx->message);
+               else
+                       snprintf(buf, sizeof(buf),
+                                       "Could not complete.<br>Error #%d.",
+                                       err);
+
+               gui_simple_popup_title_set(ctx->popup, "Error");
+               gui_simple_popup_message_set(ctx->popup, buf);
+       }
+}
+
+static void _ussd_respond(void *data, Evas_Object *o __UNUSED__,
+                               void *event_info __UNUSED__)
+{
+       USSD *ctx = data;
+       const char *markup = gui_simple_popup_entry_get(ctx->popup);
+       char *utf8;
+
+       DBG("ctx=%p, markup=%s, pending=%p, popup=%p",
+               ctx, markup, ctx->pending, ctx->popup);
+
+       if (!markup)
+               return;
+
+       /* do not respond if there is a pending ss call */
+       EINA_SAFETY_ON_TRUE_RETURN(ctx->pending != NULL);
+
+       utf8 = elm_entry_markup_to_utf8(markup);
+       EINA_SAFETY_ON_NULL_RETURN(utf8);
+
+       ctx->pending = ofono_ussd_respond(utf8, _ussd_respond_reply, ctx);
+       free(utf8);
+
+       gui_simple_popup_message_set(ctx->popup, NULL);
+       gui_simple_popup_entry_disable(ctx->popup);
+}
+
+static void _ussd_cancel_reply(void *data, OFono_Error e)
+{
+       USSD *ctx = data;
+
+       DBG("ctx=%p, e=%d, pending=%p, popup=%p",
+               ctx, e, ctx->pending, ctx->popup);
+
+       if (ctx->popup)
+               evas_object_del(ctx->popup);
+}
+
+static void _ussd_cancel(void *data, Evas_Object *o __UNUSED__,
+                               void *event_info __UNUSED__)
+{
+       USSD *ctx = data;
+       ofono_ussd_cancel(_ussd_cancel_reply, ctx);
+}
+
+static void _ofono_changed(void *data)
+{
+       USSD *ctx = data;
+       OFono_USSD_State state = ofono_ussd_state_get();
+
+       DBG("ctx=%p, state=%d (was: %d), pending=%p",
+               ctx, state, ctx->state, ctx->pending);
+
+       if (ctx->state == state)
+               return;
+
+       if (state != OFONO_USSD_STATE_USER_RESPONSE) {
+               gui_simple_popup_entry_disable(ctx->popup);
+               gui_simple_popup_button_dismiss_set(ctx->popup);
+       } else {
+               gui_simple_popup_entry_enable(ctx->popup);
+               gui_simple_popup_buttons_set(ctx->popup,
+                                               "Respond",
+                                               "dialer",
+                                               _ussd_respond,
+                                               "Cancel",
+                                               "dialer-caution",
+                                               _ussd_cancel,
+                                               ctx);
+       }
+
+       ctx->state = state;
+}
+
+static void _on_del(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__,
+                       void *event_info __UNUSED__)
+{
+       USSD *ctx = data;
+
+       DBG("ctx=%p, pending=%p, cb_changed=%p",
+               ctx, ctx->pending, ctx->cb_changed);
+
+       ctx->popup = NULL;
+
+       if (ctx->pending) {
+               ofono_ussd_cancel(NULL, NULL);
+               ofono_pending_cancel(ctx->pending);
+       }
+
+       eina_stringshare_del(ctx->message);
+       ofono_modem_changed_cb_del(ctx->cb_changed);
+}
+
+void ussd_start(const char *message)
+{
+       USSD *ctx;
+
+       EINA_SAFETY_ON_NULL_RETURN(message);
+       ctx = calloc(1, sizeof(USSD));
+       EINA_SAFETY_ON_NULL_RETURN(ctx);
+
+       ctx->message = eina_stringshare_add(message);
+       ctx->state = -1;
+       ctx->cb_changed = ofono_modem_changed_cb_add(_ofono_changed, ctx);
+
+       ctx->popup = gui_simple_popup("Supplementary Services", ctx->message);
+       evas_object_event_callback_add(ctx->popup, EVAS_CALLBACK_DEL,
+                                       _on_del, ctx);
+       _ofono_changed(ctx);
+}
diff --git a/dialer/ussd.h b/dialer/ussd.h
new file mode 100644 (file)
index 0000000..cabe77e
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _EFL_OFONO_USSD_H__
+#define _EFL_OFONO_USSD_H__ 1
+
+void ussd_start(const char *message);
+
+#endif