4 #include <Elementary.h>
11 /* timeout to change keys into modified, like 0 -> + */
12 #define MOD_TIMEOUT (1.0)
14 /* timeouts to repeat key while pressed */
15 #define REP_TIMEOUT_INIT (0.3)
16 #define REP_TIMEOUT (0.2)
18 typedef struct _Keypad
23 Ecore_Timer *mod_timeout;
24 Ecore_Timer *rep_timeout;
27 static void _number_display(Keypad *ctx)
29 const char *number = eina_strbuf_string_get(ctx->number);
30 char *s = phone_format(number);
33 elm_object_part_text_set(ctx->self, "elm.text.display", "");
34 elm_object_part_text_set(ctx->self, "elm.text.contact-and-type",
36 elm_object_part_text_set(ctx->self, "elm.text.contact", "");
37 elm_object_part_text_set(ctx->self, "elm.text.phone.type", "");
38 elm_object_signal_emit(ctx->self, "disable,save", "keypad");
39 elm_object_signal_emit(ctx->self, "disable,backspace",
41 elm_object_signal_emit(ctx->self, "hide,contact", "keypad");
45 Contact_Info *info = gui_contact_search(number, &type);
47 const char *name = contact_info_full_name_get(info);
50 snprintf(buf, sizeof(buf), "%s - %s", name, type);
52 elm_object_part_text_set(ctx->self, "elm.text.contact-and-type",
54 elm_object_part_text_set(ctx->self, "elm.text.contact", name);
55 elm_object_part_text_set(ctx->self, "elm.text.phone.type", type);
56 elm_object_signal_emit(ctx->self, "show,contact", "keypad");
58 elm_object_signal_emit(ctx->self, "hide,contact", "keypad");
59 elm_object_part_text_set(ctx->self, "elm.text.contact-and-type",
61 elm_object_part_text_set(ctx->self, "elm.text.contact", "");
62 elm_object_part_text_set(ctx->self, "elm.text.phone.type", "");
65 elm_object_part_text_set(ctx->self, "elm.text.display", s);
68 elm_object_signal_emit(ctx->self, "enable,save", "keypad");
69 elm_object_signal_emit(ctx->self, "enable,backspace", "keypad");
73 static void _imei_show(void)
75 const char *imei = ofono_modem_serial_get();
76 gui_simple_popup("IMEI Request", imei ? imei : "No modem");
77 INF("Show IMEI: %s", imei);
80 static void _pin_reply(void *data, OFono_Error error)
82 const char *title = data;
85 case OFONO_ERROR_NONE:
88 case OFONO_ERROR_INVALID_ARGS:
89 msg = "Invalid Arguments";
91 case OFONO_ERROR_INVALID_FORMAT:
92 msg = "Invalid Format";
98 gui_simple_popup(title, msg);
99 if (error == OFONO_ERROR_NONE)
105 static void _change_pin(const char *what, const char *old, const char *new)
107 DBG("ask change of %s from %s to %s", what, old, new);
108 ofono_modem_change_pin(what, old, new, _pin_reply, "PIN Change");
111 static void _reset_pin(const char *what, const char *old, const char *new)
113 DBG("ask reset of %s using %s to %s", what, old, new);
114 ofono_modem_reset_pin(what, old, new, _pin_reply, "PIN Reset");
117 static void _parse_pin(const char *str, char **old, char **new)
119 const char *p1, *p2, *p3;
120 int len1, len2, len3;
122 p1 = strchr(str, '*');
126 p2 = strchr(p1 + 1, '*');
130 p3 = strchr(p2 + 1, '#');
135 len2 = p2 - (p1 + 1);
136 len3 = p3 - (p2 + 1);
138 if ((len2 != len3) || (memcmp(p1 + 1, p2 + 1, len2) != 0)) {
139 ERR("New PIN code check failed: '%.*s' '%.*s'",
145 *old = strndup(str, len1);
146 *new = strndup(p1 + 1, len2);
151 ERR("Invalid PIN change format: %s", str);
154 static Eina_Bool _handle_if_mmi(Keypad *ctx)
156 const char *str = eina_strbuf_string_get(ctx->number);
157 size_t len = eina_strbuf_length_get(ctx->number);
162 if (len < sizeof("*#06#") - 1)
167 if (str[len - 1] != '#')
170 DBG("Possible MMI code: %s", str);
175 if (strcmp(str, "#06#") == 0) {
177 eina_strbuf_reset(ctx->number);
178 _number_display(ctx);
180 } else if (strncmp(str, "*0", 2) == 0) {
181 const char *what = NULL, *p = str + 2;
182 char *old = NULL, *new = NULL;
183 void (*action)(const char *, const char *, const char *) = NULL;
186 /* MMI codes to change PIN:
187 * - **04*OLD_PIN*NEW_PIN*NEW_PIN#
188 * - **042*OLD-PIN2*NEW_PIN2*NEW_PIN2#
191 action = _change_pin;
195 } else if (strncmp(p, "2*", 2) == 0) {
201 _parse_pin(p, &old, &new);
202 } else if (*p == '5') {
203 /* MMI codes to reset PIN:
204 * - **05*PIN_UNBLOCKING_KEY*NEW_PIN*NEW_PIN#
205 * - **052*PIN2_UNBLOCKING_KEY*NEW_PIN2*NEW_PIN2#
212 } else if (strncmp(p, "2*", 2) == 0) {
218 _parse_pin(p, &old, &new);
221 DBG("PIN management '%s' what=%s, old=%s, new=%s",
222 str, what, old, new);
223 if (action && what && old && new) {
224 action(what, old, new);
225 eina_strbuf_reset(ctx->number);
226 _number_display(ctx);
237 static void _dial_reply(void *data, OFono_Error err,
238 OFono_Call *call __UNUSED__)
242 if (err != OFONO_ERROR_NONE) {
244 snprintf(buf, sizeof(buf), "Could not call: %s",
245 eina_strbuf_string_get(ctx->number));
246 gui_simple_popup("Error", buf);
250 static void _dial(Keypad *ctx)
252 const char *number = eina_strbuf_string_get(ctx->number);
254 INF("call %s", number);
255 ofono_dial(number, NULL, _dial_reply, ctx);
256 eina_stringshare_replace(&(ctx->last), number);
257 eina_strbuf_reset(ctx->number);
258 _number_display(ctx);
261 static void _ss_initiate_reply(void *data, OFono_Error err, const char *str)
265 DBG("e=%d, str=%s", err, str);
266 if ((err == OFONO_ERROR_NOT_RECOGNIZED) ||
267 (err == OFONO_ERROR_INVALID_FORMAT))
269 else if (err == OFONO_ERROR_OFFLINE)
270 gui_simple_popup("Offline", "System is offline!");
271 else if (err != OFONO_ERROR_NONE) {
273 snprintf(buf, sizeof(buf), "Could not complete.<br>Error #%d",
275 gui_simple_popup("Error", buf);
277 gui_simple_popup(NULL, str);
280 /* Procedure as ofono/doc/mmi-codes.txt:
281 * - send number to SupplementaryServices.Initiate()
282 * - if NotRecognized is returned, then forward VoiceCallManager.Dial()
284 static void _call(Keypad *ctx)
286 const char *number = eina_strbuf_string_get(ctx->number);
287 int len = eina_strbuf_length_get(ctx->number);
289 INF("calling %s...", number);
291 if ((len > 0) && (number[len - 1] == '#'))
292 ofono_ss_initiate(number, _ss_initiate_reply, ctx);
297 static Eina_Bool _on_mod_timeout(void *data)
300 size_t len = eina_strbuf_length_get(ctx->number);
303 const char *str = eina_strbuf_string_get(ctx->number);
304 if (str[len - 1] == '0') {
305 eina_strbuf_remove(ctx->number, len - 1, len);
306 eina_strbuf_append_char(ctx->number, '+');
307 _number_display(ctx);
311 ctx->mod_timeout = NULL;
315 static Eina_Bool _on_rep_timeout(void *data)
318 size_t len = eina_strbuf_length_get(ctx->number);
321 eina_strbuf_remove(ctx->number, len - 1, len);
322 _number_display(ctx);
326 ctx->rep_timeout = NULL;
330 ecore_timer_interval_set(ctx->rep_timeout, REP_TIMEOUT);
334 static void _on_pressed(void *data, Evas_Object *obj __UNUSED__,
335 const char *emission, const char *source __UNUSED__)
338 DBG("ctx=%p, signal: %s", ctx, emission);
340 EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "pressed,"));
341 emission += strlen("pressed,");
343 if ((emission[0] >= '0') && (emission[0] <= '9')) {
344 eina_strbuf_append_char(ctx->number, emission[0]);
345 _number_display(ctx);
347 if ((emission[0] == '0') &&
348 (eina_strbuf_length_get(ctx->number) == 1)) {
349 if (ctx->mod_timeout)
350 ecore_timer_del(ctx->mod_timeout);
351 ctx->mod_timeout = ecore_timer_add(MOD_TIMEOUT,
352 _on_mod_timeout, ctx);
355 } else if (strcmp(emission, "backspace") == 0) {
356 size_t len = eina_strbuf_length_get(ctx->number);
358 eina_strbuf_remove(ctx->number, len - 1, len);
359 _number_display(ctx);
361 if (ctx->rep_timeout)
362 ecore_timer_del(ctx->rep_timeout);
363 ctx->rep_timeout = ecore_timer_add(
364 REP_TIMEOUT_INIT, _on_rep_timeout, ctx);
368 } else if (strcmp(emission, "star") == 0) {
369 eina_strbuf_append_char(ctx->number, '*');
370 _number_display(ctx);
371 } else if (strcmp(emission, "hash") == 0) {
372 eina_strbuf_append_char(ctx->number, '#');
373 _number_display(ctx);
379 static void _on_released(void *data, Evas_Object *obj __UNUSED__,
380 const char *emission,
381 const char *source __UNUSED__)
384 DBG("ctx=%p, signal: %s", ctx, emission);
386 EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "released,"));
387 emission += strlen("released,");
389 if (ctx->mod_timeout) {
390 if (emission[0] != '0')
391 ERR("Expected '0' but got '%s' instead", emission);
392 ecore_timer_del(ctx->mod_timeout);
393 ctx->mod_timeout = NULL;
396 if (ctx->rep_timeout) {
397 if (strcmp(emission, "backspace") != 0)
398 ERR("Expected 'backspace' but got '%s' instead",
400 ecore_timer_del(ctx->rep_timeout);
401 ctx->rep_timeout = NULL;
405 static void _on_clicked(void *data, Evas_Object *obj __UNUSED__,
406 const char *emission, const char *source __UNUSED__)
409 DBG("ctx=%p, signal: %s", ctx, emission);
411 EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "clicked,"));
412 emission += strlen("clicked,");
414 if (strcmp(emission, "call") == 0) {
415 if (eina_strbuf_length_get(ctx->number) > 0)
417 else if (ctx->last) {
418 eina_strbuf_append(ctx->number, ctx->last);
419 _number_display(ctx);
421 } else if (strcmp(emission, "save") == 0) {
422 ERR("TODO save contact %s!",
423 eina_strbuf_string_get(ctx->number));
427 static void _on_del(void *data, Evas *e __UNUSED__,
428 Evas_Object *obj __UNUSED__, void *event __UNUSED__)
432 if (ctx->mod_timeout)
433 ecore_timer_del(ctx->mod_timeout);
434 if (ctx->rep_timeout)
435 ecore_timer_del(ctx->rep_timeout);
437 eina_strbuf_free(ctx->number);
438 eina_stringshare_del(ctx->last);
442 Evas_Object *keypad_add(Evas_Object *parent)
445 Evas_Object *obj = gui_layout_add(parent, "keypad");
446 EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
448 ctx = calloc(1, sizeof(Keypad));
450 ctx->number = eina_strbuf_new();
452 evas_object_data_set(obj, "keypad.ctx", ctx);
454 evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
456 elm_object_signal_callback_add(obj, "pressed,*", "keypad",
458 elm_object_signal_callback_add(obj, "released,*", "keypad",
460 elm_object_signal_callback_add(obj, "clicked,*", "keypad",
463 elm_object_part_text_set(obj, "elm.text.display", "");
464 elm_object_part_text_set(ctx->self, "elm.text.contact-and-type", "");
465 elm_object_part_text_set(ctx->self, "elm.text.contact", "");
466 elm_object_part_text_set(ctx->self, "elm.text.phone.type", "");
467 elm_object_signal_emit(obj, "hide,contact", "keypad");
468 elm_object_signal_emit(obj, "disable,save", "keypad");
469 elm_object_signal_emit(obj, "disable,backspace", "keypad");
471 elm_object_focus_allow_set(obj, EINA_TRUE);
476 void keypad_number_set(Evas_Object *obj, const char *number,
480 EINA_SAFETY_ON_NULL_RETURN(obj);
481 EINA_SAFETY_ON_NULL_RETURN(number);
483 ctx = evas_object_data_get(obj, "keypad.ctx");
484 EINA_SAFETY_ON_NULL_RETURN(ctx);
486 eina_strbuf_reset(ctx->number);
487 eina_strbuf_append(ctx->number, number);
488 _number_display(ctx);