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_signal_emit(ctx->self, "disable,save", "keypad");
35 elm_object_signal_emit(ctx->self, "disable,backspace",
37 elm_object_signal_emit(ctx->self, "hide,contact", "keypad");
41 Contact_Info *info = gui_contact_search(number, &type);
43 elm_object_part_text_set(ctx->self, "elm.text.contact", contact_info_name_get(info));
44 elm_object_part_text_set(ctx->self, "elm.text.phone.type", type);
45 elm_object_signal_emit(ctx->self, "show,contact", "keypad");
47 elm_object_signal_emit(ctx->self, "hide,contact", "keypad");
49 elm_object_part_text_set(ctx->self, "elm.text.display", s);
52 elm_object_signal_emit(ctx->self, "enable,save", "keypad");
53 elm_object_signal_emit(ctx->self, "enable,backspace", "keypad");
57 static void _imei_show(void)
59 const char *imei = ofono_modem_serial_get();
60 gui_simple_popup("IMEI Request", imei ? imei : "No modem");
61 INF("Show IMEI: %s", imei);
64 static void _pin_reply(void *data, OFono_Error error)
66 const char *title = data;
69 case OFONO_ERROR_NONE:
72 case OFONO_ERROR_INVALID_ARGS:
73 msg = "Invalid Arguments";
75 case OFONO_ERROR_INVALID_FORMAT:
76 msg = "Invalid Format";
82 gui_simple_popup(title, msg);
83 if (error == OFONO_ERROR_NONE)
89 static void _change_pin(const char *what, const char *old, const char *new)
91 DBG("ask change of %s from %s to %s", what, old, new);
92 ofono_modem_change_pin(what, old, new, _pin_reply, "PIN Change");
95 static void _reset_pin(const char *what, const char *old, const char *new)
97 DBG("ask reset of %s using %s to %s", what, old, new);
98 ofono_modem_reset_pin(what, old, new, _pin_reply, "PIN Reset");
101 static void _parse_pin(const char *str, char **old, char **new)
103 const char *p1, *p2, *p3;
104 int len1, len2, len3;
106 p1 = strchr(str, '*');
110 p2 = strchr(p1 + 1, '*');
114 p3 = strchr(p2 + 1, '#');
119 len2 = p2 - (p1 + 1);
120 len3 = p3 - (p2 + 1);
122 if ((len2 != len3) || (memcmp(p1 + 1, p2 + 1, len2) != 0)) {
123 ERR("New PIN code check failed: '%.*s' '%.*s'",
129 *old = strndup(str, len1);
130 *new = strndup(p1 + 1, len2);
135 ERR("Invalid PIN change format: %s", str);
138 static Eina_Bool _handle_if_mmi(Keypad *ctx)
140 const char *str = eina_strbuf_string_get(ctx->number);
141 size_t len = eina_strbuf_length_get(ctx->number);
146 if (len < sizeof("*#06#") - 1)
151 if (str[len - 1] != '#')
154 DBG("Possible MMI code: %s", str);
159 if (strcmp(str, "#06#") == 0) {
161 eina_strbuf_reset(ctx->number);
162 _number_display(ctx);
164 } else if (strncmp(str, "*0", 2) == 0) {
165 const char *what = NULL, *p = str + 2;
166 char *old = NULL, *new = NULL;
167 void (*action)(const char *, const char *, const char *) = NULL;
170 /* MMI codes to change PIN:
171 * - **04*OLD_PIN*NEW_PIN*NEW_PIN#
172 * - **042*OLD-PIN2*NEW_PIN2*NEW_PIN2#
175 action = _change_pin;
179 } else if (strncmp(p, "2*", 2) == 0) {
185 _parse_pin(p, &old, &new);
186 } else if (*p == '5') {
187 /* MMI codes to reset PIN:
188 * - **05*PIN_UNBLOCKING_KEY*NEW_PIN*NEW_PIN#
189 * - **052*PIN2_UNBLOCKING_KEY*NEW_PIN2*NEW_PIN2#
196 } else if (strncmp(p, "2*", 2) == 0) {
202 _parse_pin(p, &old, &new);
205 DBG("PIN management '%s' what=%s, old=%s, new=%s",
206 str, what, old, new);
207 if (action && what && old && new) {
208 action(what, old, new);
209 eina_strbuf_reset(ctx->number);
210 _number_display(ctx);
221 static void _dial_reply(void *data, OFono_Error err,
222 OFono_Call *call __UNUSED__)
226 if (err != OFONO_ERROR_NONE) {
228 snprintf(buf, sizeof(buf), "Could not call: %s",
229 eina_strbuf_string_get(ctx->number));
230 gui_simple_popup("Error", buf);
234 static void _dial(Keypad *ctx)
236 const char *number = eina_strbuf_string_get(ctx->number);
238 INF("call %s", number);
239 ofono_dial(number, NULL, _dial_reply, ctx);
240 eina_stringshare_replace(&(ctx->last), number);
241 eina_strbuf_reset(ctx->number);
242 _number_display(ctx);
245 static void _ss_initiate_reply(void *data, OFono_Error err, const char *str)
249 DBG("e=%d, str=%s", err, str);
250 if ((err == OFONO_ERROR_NOT_RECOGNIZED) ||
251 (err == OFONO_ERROR_INVALID_FORMAT))
253 else if (err == OFONO_ERROR_OFFLINE)
254 gui_simple_popup("Offline", "System is offline!");
255 else if (err != OFONO_ERROR_NONE) {
257 snprintf(buf, sizeof(buf), "Could not complete.<br>Error #%d",
259 gui_simple_popup("Error", buf);
261 gui_simple_popup(NULL, str);
264 /* Procedure as ofono/doc/mmi-codes.txt:
265 * - send number to SupplementaryServices.Initiate()
266 * - if NotRecognized is returned, then forward VoiceCallManager.Dial()
268 static void _call(Keypad *ctx)
270 const char *number = eina_strbuf_string_get(ctx->number);
271 int len = eina_strbuf_length_get(ctx->number);
273 INF("calling %s...", number);
275 if ((len > 0) && (number[len - 1] == '#'))
276 ofono_ss_initiate(number, _ss_initiate_reply, ctx);
281 static Eina_Bool _on_mod_timeout(void *data)
284 size_t len = eina_strbuf_length_get(ctx->number);
287 const char *str = eina_strbuf_string_get(ctx->number);
288 if (str[len - 1] == '0') {
289 eina_strbuf_remove(ctx->number, len - 1, len);
290 eina_strbuf_append_char(ctx->number, '+');
291 _number_display(ctx);
295 ctx->mod_timeout = NULL;
299 static Eina_Bool _on_rep_timeout(void *data)
302 size_t len = eina_strbuf_length_get(ctx->number);
305 eina_strbuf_remove(ctx->number, len - 1, len);
306 _number_display(ctx);
310 ctx->rep_timeout = NULL;
314 ecore_timer_interval_set(ctx->rep_timeout, REP_TIMEOUT);
318 static void _on_pressed(void *data, Evas_Object *obj __UNUSED__,
319 const char *emission, const char *source __UNUSED__)
322 DBG("ctx=%p, signal: %s", ctx, emission);
324 EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "pressed,"));
325 emission += strlen("pressed,");
327 if ((emission[0] >= '0') && (emission[0] <= '9')) {
328 eina_strbuf_append_char(ctx->number, emission[0]);
329 _number_display(ctx);
331 if ((emission[0] == '0') &&
332 (eina_strbuf_length_get(ctx->number) == 1)) {
333 if (ctx->mod_timeout)
334 ecore_timer_del(ctx->mod_timeout);
335 ctx->mod_timeout = ecore_timer_add(MOD_TIMEOUT,
336 _on_mod_timeout, ctx);
339 } else if (strcmp(emission, "backspace") == 0) {
340 size_t len = eina_strbuf_length_get(ctx->number);
342 eina_strbuf_remove(ctx->number, len - 1, len);
343 _number_display(ctx);
345 if (ctx->rep_timeout)
346 ecore_timer_del(ctx->rep_timeout);
347 ctx->rep_timeout = ecore_timer_add(
348 REP_TIMEOUT_INIT, _on_rep_timeout, ctx);
352 } else if (strcmp(emission, "star") == 0) {
353 eina_strbuf_append_char(ctx->number, '*');
354 _number_display(ctx);
355 } else if (strcmp(emission, "hash") == 0) {
356 eina_strbuf_append_char(ctx->number, '#');
357 _number_display(ctx);
363 static void _on_released(void *data, Evas_Object *obj __UNUSED__,
364 const char *emission,
365 const char *source __UNUSED__)
368 DBG("ctx=%p, signal: %s", ctx, emission);
370 EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "released,"));
371 emission += strlen("released,");
373 if (ctx->mod_timeout) {
374 if (emission[0] != '0')
375 ERR("Expected '0' but got '%s' instead", emission);
376 ecore_timer_del(ctx->mod_timeout);
377 ctx->mod_timeout = NULL;
380 if (ctx->rep_timeout) {
381 if (strcmp(emission, "backspace") != 0)
382 ERR("Expected 'backspace' but got '%s' instead",
384 ecore_timer_del(ctx->rep_timeout);
385 ctx->rep_timeout = NULL;
389 static void _on_clicked(void *data, Evas_Object *obj __UNUSED__,
390 const char *emission, const char *source __UNUSED__)
393 DBG("ctx=%p, signal: %s", ctx, emission);
395 EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "clicked,"));
396 emission += strlen("clicked,");
398 if (strcmp(emission, "call") == 0) {
399 if (eina_strbuf_length_get(ctx->number) > 0)
401 else if (ctx->last) {
402 eina_strbuf_append(ctx->number, ctx->last);
403 _number_display(ctx);
405 } else if (strcmp(emission, "save") == 0) {
406 ERR("TODO save contact %s!",
407 eina_strbuf_string_get(ctx->number));
411 static void _on_del(void *data, Evas *e __UNUSED__,
412 Evas_Object *obj __UNUSED__, void *event __UNUSED__)
416 if (ctx->mod_timeout)
417 ecore_timer_del(ctx->mod_timeout);
418 if (ctx->rep_timeout)
419 ecore_timer_del(ctx->rep_timeout);
421 eina_strbuf_free(ctx->number);
422 eina_stringshare_del(ctx->last);
426 Evas_Object *keypad_add(Evas_Object *parent)
429 Evas_Object *obj = gui_layout_add(parent, "keypad");
430 EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
432 ctx = calloc(1, sizeof(Keypad));
434 ctx->number = eina_strbuf_new();
436 evas_object_data_set(obj, "keypad.ctx", ctx);
438 evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
440 elm_object_signal_callback_add(obj, "pressed,*", "keypad",
442 elm_object_signal_callback_add(obj, "released,*", "keypad",
444 elm_object_signal_callback_add(obj, "clicked,*", "keypad",
447 elm_object_part_text_set(obj, "elm.text.display", "");
448 elm_object_signal_emit(obj, "hide,contact", "keypad");
449 elm_object_signal_emit(obj, "disable,save", "keypad");
450 elm_object_signal_emit(obj, "disable,backspace", "keypad");
452 elm_object_focus_allow_set(obj, EINA_TRUE);
457 void keypad_number_set(Evas_Object *obj, const char *number,
461 EINA_SAFETY_ON_NULL_RETURN(obj);
462 EINA_SAFETY_ON_NULL_RETURN(number);
464 ctx = evas_object_data_get(obj, "keypad.ctx");
465 EINA_SAFETY_ON_NULL_RETURN(ctx);
467 eina_strbuf_reset(ctx->number);
468 eina_strbuf_append(ctx->number, number);
469 _number_display(ctx);