powerkey.c 105 KB
Newer Older
1 2 3 4
/**
 * @file powerkey.c
 * Power key logic for the Mode Control Entity
 * <p>
Santtu Lakkala's avatar
Santtu Lakkala committed
5
 * Copyright © 2004-2011 Nokia Corporation and/or its subsidiary(-ies).
6
 * Copyright © 2013-2019 Jolla Ltd.
7 8
 * <p>
 * @author David Weinehall <david.weinehall@nokia.com>
9 10 11
 * @author Tapio Rantala <ext-tapio.rantala@nokia.com>
 * @author Santtu Lakkala <ext-santtu.1.lakkala@nokia.com>
 * @author Irina Bezruk <ext-irina.bezruk@nokia.com>
12
 * @author Simo Piiroinen <simo.piiroinen@jollamobile.com>
13 14
 * @author Kimmo Lindholm <kimmo.lindholm@eke.fi>
 * @author Andrew den Exter <andrew.den.exter@jolla.com>
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
 *
 * mce is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * mce is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with mce.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "powerkey.h"
30
#include "tklock.h"
31
#include "evdev.h"
32

33
#include "mce-log.h"
34
#include "mce-lib.h"
35
#include "mce-setting.h"
36
#include "mce-common.h"
37 38
#include "mce-dbus.h"
#include "mce-dsme.h"
39

40 41
#include "modules/doubletap.h"

42 43
#include "systemui/dbus-names.h"

44 45 46 47
#ifdef ENABLE_WAKELOCKS
# include "libwakelock.h"
#endif

48 49
#include <linux/input.h>

50
#include <stdlib.h>
51
#include <string.h>
52 53
#include <unistd.h>
#include <fcntl.h>
54 55

#include <mce/dbus-names.h>
56
#include <mce/mode-names.h>
57

58 59
#include <libngf/ngf.h>

60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
/* ========================================================================= *
 * OVERVIEW
 *
 * There is a predefined set of actions. Of these two are dbus actions
 * that by default make mce broadcast dbus signals, but can be configured
 * to make any dbus method call with optional string argument.
 *
 * Any combination of these actions can be bound to:
 * - single power key press
 * - double power key press
 * - long power key press
 *
 * The selected actions are executed in a fixed order and actions that
 * are common to both single and double press are executed immediately
 * after powerkey is released. This allows double press configuration
 * to extend what would be done with single press without causing
 * delays for single press handling.
 *
 * Separate combinations are used depending on whether the
 * display is on or off during the 1st power key press.
 *
 * The build-in defaults are as follows
 *
 * From display off:
 * - single press - turns display on
 * - double press - turns display on and hides lockscreen (but not device lock)
 * - long press   - does nothing
 *
 * From display on:
 * - single press - turns display off and activates locksreen
 * - double press - turns display off, activates locksreen and locks device
 * - long press   - initiates shutdown (if lockscreen is not active)
 *
 * Effectively this is just as before, except for the double press
 * actions to apply device lock / wake up to home screen.
 * ========================================================================= */
spiiroin's avatar
spiiroin committed
96

97 98 99 100 101 102
/* ========================================================================= *
 * CONSTANTS
 * ========================================================================= */

#define MODULE_NAME "powerkey"

103 104 105 106 107 108 109 110 111 112 113 114 115 116
/* ========================================================================= *
 * PROTOTYPES
 * ========================================================================= */

/* ------------------------------------------------------------------------- *
 * MISC_UTIL
 * ------------------------------------------------------------------------- */

/* Null tolerant string equality predicate
 *
 * @param s1 string
 * @param s2 string
 *
 * @return true if both s1 and s2 are null or same string, false otherwise
117
 */
118 119 120 121
static inline bool eq(const char *s1, const char *s2)
{
    return (s1 && s2) ? !strcmp(s1, s2) : (s1 == s2);
}
122

123
/** String is NULL or empty predicate
124
 */
125 126 127 128
static inline bool empty(const char *s)
{
    return s == 0 || *s == 0;
}
129

130 131 132 133 134 135
static char   *pwrkey_get_token(char **ppos);
static bool    pwrkey_create_flagfile(const char *path);
static bool    pwrkey_delete_flagfile(const char *path);

/* ------------------------------------------------------------------------- *
 * PS_OVERRIDE
136
 *
137 138 139 140
 * Provides escape from stuck proximity sensor.
 * ------------------------------------------------------------------------- */

/** [setting] Power key press count for proximity sensor override */
141
static gint  pwrkey_ps_override_count = MCE_DEFAULT_POWERKEY_PS_OVERRIDE_COUNT;
142
static guint pwrkey_ps_override_count_setting_id = 0;
143 144

/** [setting] Maximum time between power key presses for proximity sensor override */
145
static gint  pwrkey_ps_override_timeout = MCE_DEFAULT_POWERKEY_PS_OVERRIDE_TIMEOUT;
146
static guint pwrkey_ps_override_timeout_setting_id = 0;
147 148 149 150 151

static void  pwrkey_ps_override_evaluate(void);

/* ------------------------------------------------------------------------- *
 * ACTION_EXEC
152
 *
153 154 155
 * Individual actions that can be taken.
 * ------------------------------------------------------------------------- */

156
static gint  pwrkey_action_blank_mode = MCE_DEFAULT_POWERKEY_BLANKING_MODE;
157
static guint pwrkey_action_blank_mode_setting_id = 0;
158

159
static void  pwrkey_action_vibrate  (void);
160 161 162 163 164
static void  pwrkey_action_shutdown (void);
static void  pwrkey_action_tklock   (void);
static void  pwrkey_action_blank    (void);
static void  pwrkey_action_unblank  (void);
static void  pwrkey_action_tkunlock (void);
165
static void  pwrkey_action_tkunlock2(void);
166 167 168
static void  pwrkey_action_devlock  (void);
static void  pwrkey_action_dbus1    (void);
static void  pwrkey_action_dbus2    (void);
169 170 171 172
static void  pwrkey_action_dbus3    (void);
static void  pwrkey_action_dbus4    (void);
static void  pwrkey_action_dbus5    (void);
static void  pwrkey_action_dbus6    (void);
173 174 175 176
static void  pwrkey_action_dbus7    (void);
static void  pwrkey_action_dbus8    (void);
static void  pwrkey_action_dbus9    (void);
static void  pwrkey_action_dbus10   (void);
177
static void  pwrkey_action_nop      (void);
178 179 180

/* ------------------------------------------------------------------------- *
 * ACTION_SETS
181
 *
182 183 184 185
 * Handle sets of individual actions.
 * ------------------------------------------------------------------------- */

typedef struct
186
{
187 188 189
    const char *name;
    void      (*func)(void);
} pwrkey_bitconf_t;
190

191
static void     pwrkey_mask_execute_cb (gpointer aptr);
192 193 194 195
static void     pwrkey_mask_execute    (uint32_t mask);
static uint32_t pwrkey_mask_from_name  (const char *name);
static uint32_t pwrkey_mask_from_names (const char *names);
static gchar   *pwrkey_mask_to_names   (uint32_t mask);
196

197 198 199 200 201
/* ------------------------------------------------------------------------- *
 * GESTURE_FILTERING
 * ------------------------------------------------------------------------- */

/** Touchscreen gesture (doubletap etc) enable mode */
202
static gint  pwrkey_gestures_enable_mode = MCE_DEFAULT_DOUBLETAP_MODE;
203 204
static guint pwrkey_gestures_enable_mode_cb_id = 0;

205
static bool  pwrkey_gestures_allowed(bool synthesized);
206
static bool  pwrkey_fpwakeup_allowed(void);
207

208 209 210 211 212 213 214 215 216 217
/* ------------------------------------------------------------------------- *
 * PWRKEY_UNBLANK
 * ------------------------------------------------------------------------- */

/** Enumeratio of possible unblank allowed predicates */
typedef enum
{
    /** Apply powerkey press rules */
    PWRKEY_UNBLANK_PREDICATE_POWERKEY,

218 219 220
    /** Apply fingerprint wakeup rules */
    PWRKEY_UNBLANK_PREDICATE_FPWAKEUP,

221 222 223 224 225 226 227 228 229 230 231
    /** Apply rules for real gesture events */
    PWRKEY_UNBLANK_PREDICATE_GESTURE_REAL,

    /** Apply rules for synthetized gesture events */
    PWRKEY_UNBLANK_PREDICATE_GESTURE_SYNTH,
} pwrkey_unblank_predicate_t;

/** Lookup table of unblank predicate names (for diagnostic logging) */
static const char * const pwrkey_unblank_predicate_name[] =
{
    [PWRKEY_UNBLANK_PREDICATE_POWERKEY]      = "powerkey",
232
    [PWRKEY_UNBLANK_PREDICATE_FPWAKEUP]      = "fpwakeup",
233 234 235 236 237 238 239 240 241 242 243 244
    [PWRKEY_UNBLANK_PREDICATE_GESTURE_REAL]  = "gesture_real",
    [PWRKEY_UNBLANK_PREDICATE_GESTURE_SYNTH] = "gesture_synth",
};

/** Currently active unblanking allowed predicate */
static pwrkey_unblank_predicate_t pwrkey_unblank_predicate =
    PWRKEY_UNBLANK_PREDICATE_POWERKEY;

static bool  pwrkey_unblank_allowed         (void);
static void  pwrkey_unblank_set_predicate_cb(gpointer aptr);
static void  pwrkey_unblank_set_predicate   (pwrkey_unblank_predicate_t predicate);

245 246 247
/* ------------------------------------------------------------------------- *
 * ACTION_TRIGGERING
 * ------------------------------------------------------------------------- */
248

249 250 251 252
typedef struct
{
    /** Actions common to single and double press */
    uint32_t mask_common;
253

254 255
    /** Actions for single press */
    uint32_t mask_single;
256

257 258
    /** Actions for double press */
    uint32_t mask_double;
259

260 261 262
    /** Actions for long press */
    uint32_t mask_long;
} pwrkey_actions_t;
263

264 265
/** Actions when power key is pressed while display is on */
static pwrkey_actions_t pwrkey_actions_from_display_on  = { 0, 0, 0, 0 };
266

267 268
/** Actions when power key is pressed while display is off */
static pwrkey_actions_t pwrkey_actions_from_display_off = { 0, 0, 0, 0 };
269

270 271 272
/** Actions on touch screen gestures */
static pwrkey_actions_t pwrkey_actions_from_gesture[POWERKEY_ACTIONS_GESTURE_COUNT] = {};

273 274 275 276
/** Currently selected power key actions; default to turning display on */
static pwrkey_actions_t *pwrkey_actions_now =
    &pwrkey_actions_from_display_off;

277 278
static gchar *pwrkey_actions_single_on             = 0;
static guint  pwrkey_actions_single_on_setting_id  = 0;
279

280 281
static gchar *pwrkey_actions_double_on             = 0;
static guint  pwrkey_actions_double_on_setting_id  = 0;
282

283 284
static gchar *pwrkey_actions_long_on               = 0;
static guint  pwrkey_actions_long_on_setting_id    = 0;
285

286 287
static gchar *pwrkey_actions_single_off            = 0;
static guint  pwrkey_actions_single_off_setting_id = 0;
288

289 290
static gchar *pwrkey_actions_double_off            = 0;
static guint  pwrkey_actions_double_off_setting_id = 0;
291

292 293
static gchar *pwrkey_actions_long_off              = 0;
static guint  pwrkey_actions_long_off_setting_id   = 0;
294

295 296 297
/** Array of setting keys for configurable touchscreen gestures */
static const char * const pwrkey_actions_gesture_key[POWERKEY_ACTIONS_GESTURE_COUNT] =
{
298 299 300 301 302 303 304 305 306 307 308
    MCE_SETTING_POWERKEY_ACTIONS_GESTURE0,
    MCE_SETTING_POWERKEY_ACTIONS_GESTURE1,
    MCE_SETTING_POWERKEY_ACTIONS_GESTURE2,
    MCE_SETTING_POWERKEY_ACTIONS_GESTURE3,
    MCE_SETTING_POWERKEY_ACTIONS_GESTURE4,
    MCE_SETTING_POWERKEY_ACTIONS_GESTURE5,
    MCE_SETTING_POWERKEY_ACTIONS_GESTURE6,
    MCE_SETTING_POWERKEY_ACTIONS_GESTURE7,
    MCE_SETTING_POWERKEY_ACTIONS_GESTURE8,
    MCE_SETTING_POWERKEY_ACTIONS_GESTURE9,
    MCE_SETTING_POWERKEY_ACTIONS_GESTURE10,
309 310 311 312 313 314 315 316 317
    MCE_SETTING_POWERKEY_ACTIONS_GESTURE11,
    MCE_SETTING_POWERKEY_ACTIONS_GESTURE12,
    MCE_SETTING_POWERKEY_ACTIONS_GESTURE13,
    MCE_SETTING_POWERKEY_ACTIONS_GESTURE14,
    MCE_SETTING_POWERKEY_ACTIONS_GESTURE15,
    MCE_SETTING_POWERKEY_ACTIONS_GESTURE16,
    MCE_SETTING_POWERKEY_ACTIONS_GESTURE17,
    MCE_SETTING_POWERKEY_ACTIONS_GESTURE18,
    MCE_SETTING_POWERKEY_ACTIONS_GESTURE19,
318 319 320 321 322
};

/** Array of default values for configurable touchscreen gestures */
static const char * const pwrkey_actions_gesture_val[POWERKEY_ACTIONS_GESTURE_COUNT] =
{
323 324 325 326 327 328 329 330 331 332 333
    MCE_DEFAULT_POWERKEY_ACTIONS_GESTURE0,
    MCE_DEFAULT_POWERKEY_ACTIONS_GESTURE1,
    MCE_DEFAULT_POWERKEY_ACTIONS_GESTURE2,
    MCE_DEFAULT_POWERKEY_ACTIONS_GESTURE3,
    MCE_DEFAULT_POWERKEY_ACTIONS_GESTURE4,
    MCE_DEFAULT_POWERKEY_ACTIONS_GESTURE5,
    MCE_DEFAULT_POWERKEY_ACTIONS_GESTURE6,
    MCE_DEFAULT_POWERKEY_ACTIONS_GESTURE7,
    MCE_DEFAULT_POWERKEY_ACTIONS_GESTURE8,
    MCE_DEFAULT_POWERKEY_ACTIONS_GESTURE9,
    MCE_DEFAULT_POWERKEY_ACTIONS_GESTURE10,
334 335 336 337 338 339 340 341 342
    MCE_DEFAULT_POWERKEY_ACTIONS_GESTURE11,
    MCE_DEFAULT_POWERKEY_ACTIONS_GESTURE12,
    MCE_DEFAULT_POWERKEY_ACTIONS_GESTURE13,
    MCE_DEFAULT_POWERKEY_ACTIONS_GESTURE14,
    MCE_DEFAULT_POWERKEY_ACTIONS_GESTURE15,
    MCE_DEFAULT_POWERKEY_ACTIONS_GESTURE16,
    MCE_DEFAULT_POWERKEY_ACTIONS_GESTURE17,
    MCE_DEFAULT_POWERKEY_ACTIONS_GESTURE18,
    MCE_DEFAULT_POWERKEY_ACTIONS_GESTURE19,
343 344 345
};

/** Array of current values for configurable touchscreen gestures */
346 347
static gchar *pwrkey_actions_gesture           [POWERKEY_ACTIONS_GESTURE_COUNT] = {};
static guint  pwrkey_actions_gesture_setting_id[POWERKEY_ACTIONS_GESTURE_COUNT] = {};
348

349 350
static void pwrkey_actions_parse           (pwrkey_actions_t *self, const char *names_single, const char *names_double, const char *names_long);

351
static void pwrkey_actions_do_gesture      (size_t gesture);
352 353 354 355
static void pwrkey_actions_do_common       (void);
static void pwrkey_actions_do_single_press (void);
static void pwrkey_actions_do_double_press (void);
static void pwrkey_actions_do_long_press   (void);
356
static bool pwrkey_actions_update          (const pwrkey_actions_t *self, gchar **names_single, gchar **names_double, gchar **names_long);
357 358 359 360 361 362 363

static bool pwrkey_actions_use_double_press(void);

static void pwrkey_actions_select          (bool display_is_on);

/* ------------------------------------------------------------------------- *
 * LONG_PRESS_TIMEOUT
364
 *
365 366
 * timer for telling apart short and long power key presses
 * ------------------------------------------------------------------------- */
367

368 369
static gint     pwrkey_long_press_delay = MCE_DEFAULT_POWERKEY_LONG_PRESS_DELAY;
static guint    pwrkey_long_press_delay_setting_id = 0;
370

371
static guint    pwrkey_long_press_timer_id = 0;
372 373 374 375 376 377 378 379 380 381 382 383

static gboolean pwrkey_long_press_timer_cb      (gpointer aptr);
static void     pwrkey_long_press_timer_start   (void);
static bool     pwrkey_long_press_timer_pending (void);
static bool     pwrkey_long_press_timer_cancel  (void);

/* ------------------------------------------------------------------------- *
 * DOUBLE_PRESS_TIMEOUT
 *
 * timer for telling apart single and double power key presses
 * ------------------------------------------------------------------------- */

384
static gint     pwrkey_double_press_delay = MCE_DEFAULT_POWERKEY_DOUBLE_PRESS_DELAY;
385
static guint    pwrkey_double_press_delay_setting_id = 0;
386 387 388 389 390 391 392 393

static guint    pwrkey_double_press_timer_id = 0;

static gboolean pwrkey_double_press_timer_cb(gpointer aptr);
static bool     pwrkey_double_press_timer_pending(void);
static bool     pwrkey_double_press_timer_cancel(void);
static void     pwrkey_double_press_timer_start(void);

394 395 396 397 398 399 400 401 402 403 404 405
/* ------------------------------------------------------------------------- *
 * NGFD_GLUE
 * ------------------------------------------------------------------------- */

static const char *xngf_state_repr    (NgfEventState state);
static void        xngf_status_cb     (NgfClient *client, uint32_t event_id, NgfEventState state, void *userdata);
static bool        xngf_create_client (void);
static void        xngf_delete_client (void);
static void        xngf_play_event    (const char *event_name);
static void        xngf_init          (void);
static void        xngf_quit          (void);

406 407 408 409 410 411 412 413 414 415 416 417
/* ------------------------------------------------------------------------- *
 * DBUS_ACTIONS
 *
 * emitting dbus signal from mce / making dbus method call to some service
 * ------------------------------------------------------------------------- */

/** Flag file for: Possibly dangerous dbus action in progress
 *
 * Used for resetting dbus action config if it causes mce to crash.
 *
 * Using tmpfs is problematic from permissions point of view, but we do
 * not want to cause flash wear by this either.
418
 */
419 420 421 422
static const char pwrkey_dbus_action_flag[]  =
    "/tmp/mce-powerkey-dbus-action.flag";

typedef struct
423
{
424 425 426 427
    const char *setting_key;
    const char *setting_def;
    gchar      *setting_val;
    guint       setting_id;
428

429 430 431 432 433 434 435
    char *destination;
    char *object;
    char *interface;
    char *member;
    char *argument;
} pwrkey_dbus_action_t;

436
static pwrkey_dbus_action_t pwrkey_dbus_action[POWEKEY_DBUS_ACTION_COUNT] =
437 438
{
    {
439 440 441 442
        .setting_key = MCE_SETTING_POWERKEY_DBUS_ACTION1,
        .setting_def = MCE_DEFAULT_POWERKEY_DBUS_ACTION1,
        .setting_val = 0,
        .setting_id  = 0,
443 444
    },
    {
445 446 447 448
        .setting_key = MCE_SETTING_POWERKEY_DBUS_ACTION2,
        .setting_def = MCE_DEFAULT_POWERKEY_DBUS_ACTION2,
        .setting_val = 0,
        .setting_id  = 0,
449 450
    },
    {
451 452 453 454
        .setting_key = MCE_SETTING_POWERKEY_DBUS_ACTION3,
        .setting_def = MCE_DEFAULT_POWERKEY_DBUS_ACTION3,
        .setting_val = 0,
        .setting_id  = 0,
455 456
    },
    {
457 458 459 460
        .setting_key = MCE_SETTING_POWERKEY_DBUS_ACTION4,
        .setting_def = MCE_DEFAULT_POWERKEY_DBUS_ACTION4,
        .setting_val = 0,
        .setting_id  = 0,
461 462
    },
    {
463 464 465 466
        .setting_key = MCE_SETTING_POWERKEY_DBUS_ACTION5,
        .setting_def = MCE_DEFAULT_POWERKEY_DBUS_ACTION5,
        .setting_val = 0,
        .setting_id  = 0,
467 468
    },
    {
469 470 471 472
        .setting_key = MCE_SETTING_POWERKEY_DBUS_ACTION6,
        .setting_def = MCE_DEFAULT_POWERKEY_DBUS_ACTION6,
        .setting_val = 0,
        .setting_id  = 0,
473
    },
474
    {
475 476 477 478
        .setting_key = MCE_SETTING_POWERKEY_DBUS_ACTION7,
        .setting_def = MCE_DEFAULT_POWERKEY_DBUS_ACTION7,
        .setting_val = 0,
        .setting_id  = 0,
479 480
    },
    {
481 482 483 484
        .setting_key = MCE_SETTING_POWERKEY_DBUS_ACTION8,
        .setting_def = MCE_DEFAULT_POWERKEY_DBUS_ACTION8,
        .setting_val = 0,
        .setting_id  = 0,
485 486
    },
    {
487 488 489 490
        .setting_key = MCE_SETTING_POWERKEY_DBUS_ACTION9,
        .setting_def = MCE_DEFAULT_POWERKEY_DBUS_ACTION9,
        .setting_val = 0,
        .setting_id  = 0,
491 492
    },
    {
493 494 495 496
        .setting_key = MCE_SETTING_POWERKEY_DBUS_ACTION10,
        .setting_def = MCE_DEFAULT_POWERKEY_DBUS_ACTION10,
        .setting_val = 0,
        .setting_id  = 0,
497
    },
498
};
499 500

static void   pwrkey_dbus_action_clear(pwrkey_dbus_action_t *self);
501
static void   pwrkey_dbus_action_reset(pwrkey_dbus_action_t *self);
502 503
static bool   pwrkey_dbus_action_is_methodcall(const pwrkey_dbus_action_t *self);
static bool   pwrkey_dbus_action_is_signal(const pwrkey_dbus_action_t *self);
504
static void   pwrkey_dbus_action_parse(pwrkey_dbus_action_t *self);
505
static gchar *pwrkey_dbus_action_to_string(const pwrkey_dbus_action_t *self);
506
static void   pwrkey_dbus_action_sanitize(pwrkey_dbus_action_t *self);
507
static void   pwrkey_dbus_action_configure(size_t action_id, bool force_reset);
508 509 510
static void   pwrkey_dbus_action_execute(size_t index);

/* ------------------------------------------------------------------------- *
511
 * POWER_KEY_STATE_MACHINE
512 513 514 515 516 517 518 519
 *
 * main logic for tracking power key presses and associated timers
 *
 * state transition graph can be generated from "powerkey.dot" file
 * ------------------------------------------------------------------------- */

/** Diplay state when power key was pressed */
static display_state_t pwrkey_stm_display_state = MCE_DISPLAY_UNDEF;
520

521
/** [setting] Power key press enable mode */
522
static gint  pwrkey_stm_enable_mode = MCE_DEFAULT_POWERKEY_MODE;
523
static guint pwrkey_stm_enable_mode_setting_id = 0;
524

525 526 527 528
static void pwrkey_stm_long_press_timeout   (void);
static void pwrkey_stm_double_press_timeout (void);
static void pwrkey_stm_powerkey_pressed     (void);
static void pwrkey_stm_powerkey_released    (void);
529

530 531
static bool pwrkey_stm_ignore_action        (void);
static bool pwrkey_stm_pending_timers       (void);
532

533
static void pwrkey_stm_rethink_wakelock     (void);
534

535 536 537
static void pwrkey_stm_store_initial_state  (void);
static void pwrkey_stm_terminate            (void);

538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
/* ------------------------------------------------------------------------- *
 * HOME_KEY_STATE_MACHINE
 * ------------------------------------------------------------------------- */

typedef enum
{
    HOMEKEY_STM_WAIT_PRESS   = 0,
    HOMEKEY_STM_WAIT_UNBLANK = 1,
    HOMEKEY_STM_SEND_SIGNAL  = 2,
    HOMEKEY_STM_WAIT_RELEASE = 3,
} homekey_stm_t;

static const char *homekey_stm_repr        (homekey_stm_t state);
static void        homekey_stm_set_state   (homekey_stm_t state);
static bool        homekey_stm_exec_step   (void);
static void        homekey_stm_eval_state  (void);
static void        homekey_stm_set_pressed (bool pressed);

556 557 558 559 560
/* ------------------------------------------------------------------------- *
 * DBUS_IPC
 *
 * handling incoming and outgoing dbus messages
 * ------------------------------------------------------------------------- */
561

562
static void     pwrkey_dbus_send_signal(const char *sig, const char *arg);
563

564
static gboolean pwrkey_dbus_trigger_event_cb(DBusMessage *const req);
565
static gboolean pwrkey_dbus_ignore_incoming_call_cb(DBusMessage *const req);
566 567 568 569 570

static void     pwrkey_dbus_init(void);
static void     pwrkey_dbus_quit(void);

/* ------------------------------------------------------------------------- *
571
 * DYNAMIC_SETTINGS
572 573 574 575
 *
 * tracking powerkey related runtime changeable settings
 * ------------------------------------------------------------------------- */

576
static gint     pwrkey_setting_sanitize_id = 0;
577

578 579 580
static void     pwrkey_setting_sanitize_action_masks(void);
static void     pwrkey_setting_sanitize_dbus_actions(void);

581 582 583 584
static gboolean pwrkey_setting_sanitize_cb     (gpointer aptr);
static void     pwrkey_setting_sanitize_now    (void);
static void     pwrkey_setting_sanitize_later  (void);
static void     pwrkey_setting_sanitize_cancel (void);
585

586 587
static bool     pwrkey_setting_handle_gesture  (const GConfValue *gcv, guint id);
static void     pwrkey_setting_cb              (GConfClient *const gcc, const guint id, GConfEntry *const entry, gpointer const data);
588

589 590
static void     pwrkey_setting_init            (void);
static void     pwrkey_setting_quit            (void);
591 592 593 594 595 596

/* ------------------------------------------------------------------------- *
 * DATAPIPE_HANDLING
 *
 * reacting to state changes / input from other mce modules
 * ------------------------------------------------------------------------- */
597

598
static void pwrkey_datapipe_keypress_event_cb(gconstpointer const data);
599
static void pwrkey_datapipe_ngfd_service_state_cb(gconstpointer data);
600
static void pwrkey_datapipe_system_state_cb(gconstpointer data);
601
static void pwrkey_datapipe_devicelock_state_cb(gconstpointer data);
602
static void pwrkey_datapipe_display_state_curr_cb(gconstpointer data);
603
static void pwrkey_datapipe_display_state_next_cb(gconstpointer data);
604 605
static void pwrkey_datapipe_lid_sensor_filtered_cb(gconstpointer data);
static void pwrkey_datapipe_proximity_sensor_actual_cb(gconstpointer data);
606 607
static void pwrkey_datapipe_call_state_cb(gconstpointer data);
static void pwrkey_datapipe_alarm_ui_state_cb(gconstpointer data);
608 609 610
static void pwrkey_datapipe_devicelock_service_state_cb(gconstpointer data);
static void pwrkey_datapipe_enroll_in_progress_cb(gconstpointer data);
static void pwrkey_datapipe_ngfd_event_request_cb(gconstpointer data);
611

612 613
static void pwrkey_datapipe_init(void);
static void pwrkey_datapipe_quit(void);
614 615 616 617 618 619 620 621 622 623 624 625 626

/* ------------------------------------------------------------------------- *
 * MODULE_INTEFACE
 * ------------------------------------------------------------------------- */

gboolean mce_powerkey_init(void);
void mce_powerkey_exit(void);

/* ========================================================================= *
 * MISC_UTIL
 * ========================================================================= */

/** Parse element from comma separated string list
627
 */
628 629
static char *
pwrkey_get_token(char **ppos)
630
{
631 632
    char *pos = *ppos;
    char *beg = pos;
633

634 635
    if( !pos )
        goto cleanup;
636

637 638 639 640 641 642
    for( ; *pos; ++pos ) {
        if( *pos != ',' )
            continue;
        *pos++ = 0;
        break;
    }
643

644 645
cleanup:
    return *ppos = pos, beg;
646 647
}

648
/** Create an empty flag file
649
 *
650 651 652
 * @param path Path to the file to create
 *
 * @return true if file was created, false otherwise
653
 */
654
static bool pwrkey_create_flagfile(const char *path)
655
{
656 657 658 659 660 661 662 663 664
    bool created = false;

    int fd = open(path, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0666);
    if( fd != -1 ) {
        close(fd);
        created = true;
    }

    return created;
665 666
}

667 668 669 670 671
/** Delete a flag file
 *
 * @param path Path to the file to create
 *
 * @return true if file was removed, false otherwise
672 673
 */

674 675 676
static bool pwrkey_delete_flagfile(const char *path)
{
    bool deleted = false;
677

678 679 680
    if( unlink(path) == 0 ) {
        deleted = true;
    }
681

682
    return deleted;
683 684
}

685 686 687 688 689
/* ========================================================================= *
 * DATAPIPE_HANDLING
 * ========================================================================= */

/** System state; is undefined at bootup, can't assume anything */
690
static system_state_t system_state = MCE_SYSTEM_STATE_UNDEF;
691

692 693 694
/** Cached devicelock_state ; assume unknown */
static devicelock_state_t devicelock_state = DEVICELOCK_STATE_UNDEFINED;

695
/** Current display state; undefined initially, can't assume anything */
696
static display_state_t display_state_curr = MCE_DISPLAY_UNDEF;
697

698 699 700 701
/** Next Display state; undefined initially, can't assume anything */
static display_state_t display_state_next = MCE_DISPLAY_UNDEF;

/** Lid cover policy state; assume unknown */
702
static cover_state_t lid_sensor_filtered = COVER_UNDEF;
703 704

/** Actual proximity state; assume not covered */
705
static cover_state_t proximity_sensor_actual = COVER_UNDEF;
706 707

/** NGFD availability */
708
static service_state_t ngfd_service_state = SERVICE_STATE_UNDEF;
709

710 711 712 713 714 715
/** Cached alarm ui state */
static alarm_ui_state_t alarm_ui_state = MCE_ALARM_UI_OFF_INT32;

/** Cached call state */
static call_state_t call_state = CALL_STATE_NONE;

716
/** devicelock dbus name is reserved; assume unknown */
717
static service_state_t devicelock_service_state = SERVICE_STATE_UNDEF;
718

719 720 721
/** Cached ongoing fingerprint enroll; assume not */
static bool enroll_in_progress = false;

722 723 724
/** Use powerkey for blanking during incoming calls */
static bool pwrkey_ignore_incoming_call = false;

725 726 727 728
/* ========================================================================= *
 * PS_OVERRIDE
 * ========================================================================= */

729 730 731 732 733 734 735 736 737 738
/** Provide an emergency way out from stuck proximity sensor
 *
 * If the proximity sensor is dirty/faulty and stuck to "covered"
 * state, it can leave the phone in a state where it is impossible
 * to do anything about incoming call, ringing alarm.
 *
 * To offer somekind of remedy for the situation, this function
 * allows user to force proximity sensor to "uncovered" state
 * by rapidly pressing power button several times.
 */
739 740 741 742 743 744 745 746 747 748 749 750 751
static void
pwrkey_ps_override_evaluate(void)
{
    static int64_t t_last  = 0;
    static gint    count   = 0;

    /* If the feature is disabled, just reset the counter */
    if( pwrkey_ps_override_count   <= 0 ||
        pwrkey_ps_override_timeout <= 0 ) {
        t_last = 0, count = 0;
        goto EXIT;
    }

752
    /* If neither sensor is not covered, just reset the counter */
753
    if( proximity_sensor_actual == COVER_OPEN &&
754
        lid_sensor_filtered != COVER_CLOSED ) {
755 756 757 758
        t_last = 0, count = 0;
        goto EXIT;
    }

759
    int64_t t_now = mce_lib_get_boot_tick();
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780

    /* If the previous power key press was too far in
     * the past, start counting from zero again */

    if( t_now > t_last + pwrkey_ps_override_timeout ) {
        mce_log(LL_DEBUG, "ps override count restarted");
        count = 0;
    }

    t_last = t_now;

    /* If configured number of power key presses within the time
     * limits has been reached, force proximity sensor state to
     * "uncovered".
     *
     * This should allow touch input ungrabbing and turning
     * display on during incoming call / alarm.
     *
     * If sensor gets unstuck and new proximity readings are
     * received, this override will be automatically undone.
     */
781 782 783 784 785 786

    if( ++count != pwrkey_ps_override_count ) {
        mce_log(LL_DEBUG, "ps override count = %d", count);
        goto EXIT;
    }

787
    if( proximity_sensor_actual == COVER_CLOSED ) {
788 789
        mce_log(LL_CRIT, "assuming stuck proximity sensor;"
                " faking uncover event");
790 791

        /* Force cached proximity state to "open" */
792
        datapipe_exec_full(&proximity_sensor_actual_pipe,
793
                           GINT_TO_POINTER(COVER_OPEN));
794
    }
795

796
    if( lid_sensor_filtered == COVER_CLOSED ) {
797 798 799 800
        mce_log(LL_CRIT, "assuming stuck lid sensor;"
                " resetting validation data");

        /* Reset lid sensor validation data */
801
        datapipe_exec_full(&lid_sensor_is_working_pipe,
802
                           GINT_TO_POINTER(false));
803 804 805
    }

    t_last = 0, count = 0;
806 807 808

EXIT:

809
    return;
810 811
}

812 813 814 815
/* ========================================================================= *
 * ACTION_EXEC
 * ========================================================================= */

816 817 818 819 820 821 822
static void
pwrkey_action_vibrate(void)
{
    mce_log(LL_DEBUG, "Requesting vibrate");
    xngf_play_event("pwrkey");
}

823 824 825 826 827 828
static void
pwrkey_action_shutdown(void)
{
    submode_t submode = mce_get_submode_int32();

    /* Do not shutdown if the tklock is active */
829
    if( submode & MCE_SUBMODE_TKLOCK )
830 831 832 833
        goto EXIT;

    mce_log(LL_DEVEL, "Requesting shutdown");
    mce_dsme_request_normal_shutdown();
834 835

EXIT:
836
    return;
837 838
}

839 840 841
static void
pwrkey_action_tklock(void)
{
842
    tklock_request_t request = TKLOCK_REQUEST_ON;
843
    mce_datapipe_request_tklock(request);
844
}
845

846 847 848 849
static void
pwrkey_action_tkunlock(void)
{
    /* Only unlock if we are in/entering fully powered on display state */
850
    switch( display_state_next ) {
851 852 853 854 855 856 857 858
    case MCE_DISPLAY_ON:
    case MCE_DISPLAY_DIM:
        break;

    default:
        goto EXIT;
    }

859
    tklock_request_t request = TKLOCK_REQUEST_OFF;
860 861 862

    /* Even if powerkey actions are allowed to work while proximity
     * sensor is covered, we must not deactivatie the lockscreen */
863
    if( proximity_sensor_actual != COVER_OPEN ) {
864
        mce_log(LL_DEBUG, "Proximity sensor %s; rejecting tklock=%s",
865 866
                proximity_state_repr(proximity_sensor_actual),
                tklock_request_repr(request));
867 868 869
        goto EXIT;
    }

870
    mce_datapipe_request_tklock(request);
871
EXIT:
872
    return;
873 874
}

875 876 877 878 879 880 881 882 883 884 885 886
static void
pwrkey_action_tkunlock2(void)
{
    if( devicelock_state != DEVICELOCK_STATE_UNLOCKED ) {
        mce_log(LL_DEBUG, "devicelock_state=%s; rejecting 'tkunlock2' action",
                devicelock_state_repr(devicelock_state));
    }
    else {
        pwrkey_action_tkunlock();
    }
}

887 888
static void
pwrkey_action_blank(void)
889
{
890
    display_state_t request = MCE_DISPLAY_OFF;
891

892 893 894 895
    switch( pwrkey_action_blank_mode ) {
    case PWRKEY_BLANK_TO_LPM:
        request = MCE_DISPLAY_LPM_ON;
        break;
896

897 898 899 900
    case PWRKEY_BLANK_TO_OFF:
    default:
            break;
    }
901

902 903
    mce_log(LL_DEBUG, "Requesting display=%s",
            display_state_repr(request));
904
    mce_datapipe_request_display_state(request);
905
}
906

907 908 909
static void
pwrkey_action_unblank(void)
{
910 911 912 913 914 915 916 917 918 919 920 921 922 923
    /* Special case: Even if incoming call is beeing ignored, do not
     * allow unblanking via power key while proximity sensor is covered.
     *
     * Silencing ringing via pressing the power key through fabric
     * of a pocket easily leads to several power key presses getting
     * emitted and we do not want the display to get activated by such
     * activity.
     */
    if( call_state == CALL_STATE_RINGING ) {
        if( !pwrkey_ignore_incoming_call ) {
            mce_log(LL_DEVEL, "skip unblank; incoming call not ignored");
            goto EXIT;
        }

924
        if( proximity_sensor_actual != COVER_OPEN ) {
925 926 927 928 929
            mce_log(LL_DEVEL, "skip unblank; proximity covered/unknown");
            goto EXIT;
        }
    }

930 931 932 933 934
    if( !pwrkey_unblank_allowed() ) {
        mce_log(LL_DEVEL, "skip unblank; predicate condition not met");
        goto EXIT;
    }

935 936 937
    display_state_t request = MCE_DISPLAY_ON;
    mce_log(LL_DEBUG, "Requesting display=%s",
            display_state_repr(request));
938
    mce_tklock_unblank(request);
939 940 941

EXIT:
    return;
942 943
}

944 945
static void
pwrkey_action_devlock(void)
946
{
947 948 949
    static const char service[]   = DEVICELOCK_SERVICE;
    static const char object[]    = DEVICELOCK_REQUEST_PATH;
    static const char interface[] = DEVICELOCK_REQUEST_IF;
950
    static const char method[]    = "setState";
951
    dbus_int32_t      request     = DEVICELOCK_STATE_LOCKED;
952

953
    if( devicelock_service_state != SERVICE_STATE_RUNNING ) {
954
        mce_log(LL_WARN, "devicelock service state is %s; skip %s request",
955 956
                service_state_repr(devicelock_service_state),
                devicelock_state_repr(request));
957 958 959
        goto EXIT;
    }

960
    mce_log(LL_DEBUG, "Requesting devicelock=%s",
961
            devicelock_state_repr(request));
962 963

    dbus_send(service, object, interface, method, 0,
964
              DBUS_TYPE_INT32, &request,
965
              DBUS_TYPE_INVALID);
966 967
EXIT:
    return;
968 969
}

970 971 972 973 974 975 976 977 978 979 980 981
static void
pwrkey_action_dbus1(void)
{
    pwrkey_dbus_action_execute(0);
}

static void
pwrkey_action_dbus2(void)
{
    pwrkey_dbus_action_execute(1);
}

982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
static void
pwrkey_action_dbus3(void)
{
    pwrkey_dbus_action_execute(2);
}

static void
pwrkey_action_dbus4(void)
{
    pwrkey_dbus_action_execute(3);
}

static void
pwrkey_action_dbus5(void)
{
    pwrkey_dbus_action_execute(4);
}

static void
pwrkey_action_dbus6(void)
{
    pwrkey_dbus_action_execute(5);
}

1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
static void
pwrkey_action_dbus7(void)
{
    pwrkey_dbus_action_execute(6);
}

static void
pwrkey_action_dbus8(void)
{
    pwrkey_dbus_action_execute(7);
}

static void
pwrkey_action_dbus9(void)
{
    pwrkey_dbus_action_execute(8);
}

static void
pwrkey_action_dbus10(void)
{
    pwrkey_dbus_action_execute(9);
}

1030 1031 1032 1033 1034 1035
static void
pwrkey_action_nop(void)
{
    /* Do nothing */
}

1036 1037 1038 1039 1040
/* ========================================================================= *
 * ACTION_SETS
 * ========================================================================= */

/** Config string to callback function mapping
1041
 *
1042 1043 1044 1045
 * The configured actions are executed in order defined by this array.
 *
 * This is needed for determining actions that common to both single and
 * double press handling.
1046
 */
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
static const pwrkey_bitconf_t pwrkey_action_lut[] =
{
    // Direction: ON->OFF
    {
        .name = "blank",
        .func = pwrkey_action_blank,
    },
    {
        .name = "tklock",
        .func = pwrkey_action_tklock,
    },
    {
        .name = "devlock",
        .func = pwrkey_action_devlock,
    },
    {
        .name = "shutdown",
        .func = pwrkey_action_shutdown,
    },
1066 1067 1068 1069
    {
        .name = "vibrate",
        .func = pwrkey_action_vibrate,
    },
1070 1071 1072 1073 1074 1075

    // Direction: OFF->ON
    {
        .name = "unblank",
        .func = pwrkey_action_unblank,
    },
1076 1077 1078 1079
    {
        .name = "tkunlock2",
        .func = pwrkey_action_tkunlock2,
    },
1080 1081 1082 1083
    {
        .name = "tkunlock",
        .func = pwrkey_action_tkunlock,
    },
1084 1085 1086 1087 1088 1089

    // D-Bus actions
    {
        .name = "dbus1",
        .func = pwrkey_action_dbus1,
    },
1090 1091 1092 1093
    {
        .name = "dbus2",
        .func = pwrkey_action_dbus2,
    },
1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
    {
        .name = "dbus3",
        .func = pwrkey_action_dbus3,
    },
    {
        .name = "dbus4",
        .func = pwrkey_action_dbus4,
    },
    {
        .name = "dbus5",
        .func = pwrkey_action_dbus5,
    },
    {
        .name = "dbus6",
        .func = pwrkey_action_dbus6,
    },
1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125
    {
        .name = "dbus7",
        .func = pwrkey_action_dbus7,
    },
    {
        .name = "dbus8",
        .func = pwrkey_action_dbus8,
    },
    {
        .name = "dbus9",
        .func = pwrkey_action_dbus9,
    },
    {
        .name = "dbus10",
        .func = pwrkey_action_dbus10,
    },
1126 1127 1128 1129 1130 1131

    // Low priority placeholder/dummy action
    {
        .name = "nop",
        .func = pwrkey_action_nop,
    },
1132 1133
};

1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145
static void pwrkey_mask_execute_cb(gpointer aptr)
{
    const char *name = aptr;
    for( size_t i = 0; i < G_N_ELEMENTS(pwrkey_action_lut); ++i ) {
        if( strcmp(pwrkey_action_lut[i].name, name) )
            continue;
        mce_log(LL_DEBUG, "* exec(%s)", name);
        pwrkey_action_lut[i].func();
        break;
    }
}

1146 1147 1148 1149 1150
static void
pwrkey_mask_execute(uint32_t mask)
{
    for( size_t i = 0; i < G_N_ELEMENTS(pwrkey_action_lut); ++i ) {
        if( mask & (1u << i) ) {
1151 1152 1153 1154 1155
            const char *name = pwrkey_action_lut[i].name;
            mce_log(LL_DEBUG, "* queue(%s)", name);
            common_on_proximity_schedule(MODULE_NAME,
                                         pwrkey_mask_execute_cb,
                                         (gpointer)name);
1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191
        }
    }
}

static uint32_t
pwrkey_mask_from_name(const char *name)
{
    uint32_t mask = 0;
    for( size_t i = 0; i < G_N_ELEMENTS(pwrkey_action_lut); ++i ) {
        if( strcmp(pwrkey_action_lut[i].name, name) )
            continue;
        mask |= 1u << i;
        break;
    }
    return mask;
}

static uint32_t
pwrkey_mask_from_names(const char *names)
{
    uint32_t  mask = 0;
    char     *work = 0;
    char     *pos;
    char     *end;

    if( !names )
        goto EXIT;

    if( !(work = strdup(names)) )
        goto EXIT;

    for( pos = work; pos; pos = end ) {
        if( (end = strchr(pos, ',')) )
            *end++ = 0;
        mask |= pwrkey_mask_from_name(pos);
    }
1192 1193

EXIT:
1194 1195 1196
    free(work);

    return mask;
1197 1198
}

1199 1200
static gchar *
pwrkey_mask_to_names(uint32_t mask)
1201
{
1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
    char tmp[256];
    char *pos = tmp;
    char *end = tmp + sizeof tmp - 1;

    auto void add(const char *str)
    {
        while( pos < end && *str )
            *pos++ = *str++;
    };

    for( size_t i = 0; i < G_N_ELEMENTS(pwrkey_action_lut); ++i ) {
        if( mask & (1u << i) ) {
            if( pos > tmp )
                add(",");
            add(pwrkey_action_lut[i].name);
        }
    }
    *pos = 0;

    return g_strdup(tmp);
}

1224 1225 1226 1227 1228 1229 1230
/* ------------------------------------------------------------------------- *
 * GESTURE_FILTERING
 * ------------------------------------------------------------------------- */

/** Predicate for: touchscreen gesture actions are allowed
 */
static bool
1231
pwrkey_gestures_allowed(bool synthesized)
1232 1233 1234 1235 1236 1237 1238 1239
{
    bool allowed = false;

    /* Check enable setting */
    switch( pwrkey_gestures_enable_mode ) {
    case DBLTAP_ENABLE_ALWAYS:
        break;

1240 1241 1242 1243 1244 1245 1246 1247 1248 1249
    case DBLTAP_ENABLE_NEVER:
        if( !synthesized ) {
            mce_log(LL_DEVEL, "[gesture] ignored due to setting=never");
            goto EXIT;
        }
        /* Synthesized events (e.g. double tap from lpm) are implicitly
         * subjected to proximity rules.
         *
         * Fall through */

1250 1251
    default:
    case DBLTAP_ENABLE_NO_PROXIMITY:
1252
        if( lid_sensor_filtered == COVER_CLOSED ) {
1253 1254 1255
            mce_log(LL_DEVEL, "[gesture] ignored due to lid=closed");
            goto EXIT;
        }
1256
        if( proximity_sensor_actual == COVER_CLOSED ) {
1257 1258 1259 1260 1261 1262 1263
            mce_log(LL_DEVEL, "[gesture] ignored due to proximity");
            goto EXIT;
        }
        break;
    }

    switch( system_state ) {
1264 1265
    case MCE_SYSTEM_STATE_USER:
    case MCE_SYSTEM_STATE_ACTDEAD:
1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299
      break;
    default:
      mce_log(LL_DEVEL, "[gesture] ignored due to system state");
        goto EXIT;
    }

    /* Note: In case we happen to be in middle of display state transition
     *       the double tap blocking must use the next stable display state
     *       rather than the current - potentially transitional - state.
     */
    switch( display_state_next )
    {
    case MCE_DISPLAY_OFF:
    case MCE_DISPLAY_LPM_OFF:
    case MCE_DISPLAY_POWER_DOWN:
    case MCE_DISPLAY_LPM_ON:
        break;

    default:
    case MCE_DISPLAY_ON:
    case MCE_DISPLAY_DIM:
    case MCE_DISPLAY_POWER_UP:
    case MCE_DISPLAY_UNDEF:
        mce_log(LL_DEVEL, "[gesture] ignored due to display state");
        goto EXIT;
    }

    allowed = true;

EXIT:

    return allowed;
}

1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357
/** Predicate for: fpwakeup actions are allowed
 */
static bool
pwrkey_fpwakeup_allowed(void)
{
    bool allowed = false;

    /* Only in USER state */
    if( system_state  != MCE_SYSTEM_STATE_USER ) {
        mce_log(LL_DEVEL, "[fpwakeup] ignored due to system_state=%s",
                system_state_repr(system_state));
        goto EXIT;
    }

    /* Not while lid is closed or proximity sensor covered */
    if( lid_sensor_filtered == COVER_CLOSED ) {
        mce_log(LL_DEVEL, "[gesture] ignored due to lid=%s",
                cover_state_repr(lid_sensor_filtered));
        goto EXIT;
    }

    if( proximity_sensor_actual == COVER_CLOSED ) {
        mce_log(LL_DEVEL, "[gesture] ignored due to proximity=%s",
                proximity_state_repr(proximity_sensor_actual));
        goto EXIT;
    }

    /* To have something sensible to do with fpwakeup
     * - display must be off, or
     * - display is on and lockscreen active
     */
    submode_t submode = mce_get_submode_int32();

    switch( display_state_next )
    {
    case MCE_DISPLAY_LPM_ON:
    case MCE_DISPLAY_LPM_OFF:
    case MCE_DISPLAY_OFF:
        break;

    case MCE_DISPLAY_DIM:
    case MCE_DISPLAY_ON:
        if( !(submode & MCE_SUBMODE_TKLOCK) ) {
            mce_log(LL_DEVEL, "[fpwakeup] ignored due to tklock=false");
            goto EXIT;
        }
        break;

    default:
        goto EXIT;
    }

    allowed = true;

EXIT:
    return allowed;
}

1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373
/* ========================================================================= *
 * PWRKEY_UNBLANK
 * ========================================================================= */

/** Check if unblanking is allowed according to currently active rules
 *
 * @return true if unblanking is allowed, false otherwise
 */
static bool
pwrkey_unblank_allowed(void)
{
    bool allowed = false;
    switch( pwrkey_unblank_predicate ) {
    case PWRKEY_UNBLANK_PREDICATE_POWERKEY:
        allowed = !pwrkey_stm_ignore_action();
        break;
1374 1375 1376
    case PWRKEY_UNBLANK_PREDICATE_FPWAKEUP:
        allowed = pwrkey_fpwakeup_allowed();
        break;
1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417
    case PWRKEY_UNBLANK_PREDICATE_GESTURE_REAL:
        allowed = pwrkey_gestures_allowed(false);
        break;
    case PWRKEY_UNBLANK_PREDICATE_GESTURE_SYNTH:
        allowed = pwrkey_gestures_allowed(true);
        break;
    default:
        break;
    }
    mce_log(LL_DEBUG, "evaluate predicate %s => %s",
            pwrkey_unblank_predicate_name[pwrkey_unblank_predicate],
            allowed ? "allowed" : "denied");
    return allowed;
}

/** On-proximity callback for selecting unblank rules
 *
 * @param aptr unblank predicate to use (as void pointer)
 */
static void
pwrkey_unblank_set_predicate_cb(gpointer aptr)
{
    pwrkey_unblank_predicate = GPOINTER_TO_INT(aptr);
    mce_log(LL_DEBUG, "execute predicate = %s",
            pwrkey_unblank_predicate_name[pwrkey_unblank_predicate]);
}

/** Select which rules apply in delayed on-proximity action handling
 *
 * @param predicate unblank predicate to use (as void pointer)
 */
static void
pwrkey_unblank_set_predicate(pwrkey_unblank_predicate_t predicate)
{
    mce_log(LL_DEBUG, "schedule predicate = %s",
            pwrkey_unblank_predicate_name[predicate]);
    common_on_proximity_schedule(MODULE_NAME,
                                 pwrkey_unblank_set_predicate_cb,
                                 GINT_TO_POINTER(predicate));
}

1418 1419 1420
/* ========================================================================= *
 * ACTION_TRIGGERING
 * ========================================================================= */
1421

1422 1423 1424
static void
pwrkey_actions_do_gesture(size_t gesture)
{
1425 1426
    /* Extract modifier bits */
    bool synthetized = (gesture & GESTURE_SYNTHESIZED) != 0;
1427 1428 1429

    gesture &= ~GESTURE_SYNTHESIZED;

1430 1431 1432 1433
    /* Treat unconfigurable gestures as doubletaps */
    if( gesture >= POWERKEY_ACTIONS_GESTURE_COUNT )
        gesture = GESTURE_DOUBLETAP;

1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451
    /* Check settings, proximity sensor state, etc */
    pwrkey_unblank_predicate_t predicate = synthetized
        ? PWRKEY_UNBLANK_PREDICATE_GESTURE_SYNTH
        : PWRKEY_UNBLANK_PREDICATE_GESTURE_REAL;

    switch( gesture ) {
    case GESTURE_FPWAKEUP:
        if( !pwrkey_fpwakeup_allowed() )
            goto EXIT;
        predicate = PWRKEY_UNBLANK_PREDICATE_FPWAKEUP;
        break;
    default:
        if( !pwrkey_gestures_allowed(synthetized) )
            goto EXIT;
        break;
    }

    pwrkey_unblank_set_predicate(predicate);
1452 1453 1454 1455 1456 1457
    pwrkey_mask_execute(pwrkey_actions_from_gesture[gesture].mask_single);

EXIT:
    return;
}

1458 1459 1460
static void
pwrkey_actions_do_common(void)
{
1461
    pwrkey_unblank_set_predicate(PWRKEY_UNBLANK_PREDICATE_POWERKEY);
1462
    pwrkey_mask_execute(pwrkey_actions_now->mask_common);
1463 1464
}

1465 1466 1467
static void
pwrkey_actions_do_single_press(void)
{
1468
    pwrkey_unblank_set_predicate(PWRKEY_UNBLANK_PREDICATE_POWERKEY);
1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480
    pwrkey_mask_execute(pwrkey_actions_now->mask_single);
}

static bool
pwrkey_actions_use_double_press(void)
{
    return pwrkey_actions_now->mask_double != 0;
}

static void
pwrkey_actions_do_double_press(void)
{
1481
    pwrkey_unblank_set_predicate(PWRKEY_UNBLANK_PREDICATE_POWERKEY);
1482 1483 1484 1485 1486 1487 1488 1489
    pwrkey_mask_execute(pwrkey_actions_now->mask_double);
}

static void
pwrkey_actions_do_long_press(void)
{
    /* The action configuration applies only in the USER mode */

1490
    switch( system_state ) {
1491 1492
    case MCE_SYSTEM_STATE_SHUTDOWN:
    case MCE_SYSTEM_STATE_REBOOT:
1493 1494 1495
        /* Ignore if we're already shutting down/rebooting */
        break;

1496
    case MCE_SYSTEM_STATE_ACTDEAD:
1497 1498
        /* Activate power on led pattern and power up to user mode*/
        mce_log(LL_DEBUG, "activate MCE_LED_PATTERN_POWER_ON");
1499 1500
        datapipe_exec_full(&led_pattern_activate_pipe,
                           MCE_LED_PATTERN_POWER_ON);
1501 1502 1503
        mce_dsme_request_powerup();
        break;

1504
    case MCE_SYSTEM_STATE_USER:
spiiroin's avatar
spiiroin committed
1505
        /* Apply configured actions */
1506
        pwrkey_unblank_set_predicate(PWRKEY_UNBLANK_PREDICATE_POWERKEY);
spiiroin's avatar
spiiroin committed
1507
        pwrkey_mask_execute(pwrkey_actions_now->mask_long);
1508 1509 1510 1511
        break;

    default:
        /* Default to powering off */
1512 1513
        mce_log(LL_WARN, "Requesting shutdown from state: %s",
                system_state_repr(system_state));
1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528
        mce_dsme_request_normal_shutdown();
        break;
    }
}

static bool
pwrkey_actions_update(const pwrkey_actions_t *self,
                      gchar **names_single,
                      gchar **names_double,
                      gchar **names_long)
{
    bool changed = false;

    auto void update(gchar **prev, gchar *curr)
    {
1529
        if( prev && !eq(*prev, curr) )
1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592
            changed = true, g_free(*prev), *prev = curr, curr = 0;
        g_free(curr);
    }

    update(names_single,
           pwrkey_mask_to_names(self->mask_single | self->mask_common));

    update(names_double,
           pwrkey_mask_to_names(self->mask_double | self->mask_common));

    update(names_long,
           pwrkey_mask_to_names(self->mask_long));

    return changed;
}

static void
pwrkey_actions_parse(pwrkey_actions_t *self,
                     const char *names_single,
                     const char *names_double,
                     const char *names_long)
{
    /* Parse from configuration strings */
    self->mask_common = 0;
    self->mask_single = pwrkey_mask_from_names(names_single);
    self->mask_double = pwrkey_mask_from_names(names_double);
    self->mask_long   = pwrkey_mask_from_names(names_long);

    /* Separate leading actions that are common to both
     * single and double press */
    uint32_t diff = self->mask_single ^ self->mask_double;
    uint32_t mask = (diff - 1) & ~diff;
    uint32_t comm = self->mask_single & self->mask_double & mask;

    self->mask_common |=  comm;
    self->mask_single &= ~comm;
    self->mask_double &= ~comm;
}

static void pwrkey_actions_select(bool display_is_on)
{
    if( display_is_on )
        pwrkey_actions_now = &pwrkey_actions_from_display_on;
    else
        pwrkey_actions_now = &pwrkey_actions_from_display_off;
}

/* ========================================================================= *
 * LONG_PRESS_TIMEOUT
 * ========================================================================= */

static gboolean pwrkey_long_press_timer_cb(gpointer aptr)
{
    (void) aptr;

    if( !pwrkey_long_press_timer_id )
        goto EXIT;

    pwrkey_long_press_timer_id = 0;

    pwrkey_stm_long_press_timeout();

    pwrkey_stm_rethink_wakelock();
1593 1594

EXIT:
1595 1596

    return FALSE;
1597 1598
}

1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618
static bool
pwrkey_long_press_timer_pending(void)
{
    return pwrkey_long_press_timer_id != 0;
}

static bool
pwrkey_long_press_timer_cancel(void)
{
    bool canceled = false;
    if( pwrkey_long_press_timer_id ) {
        g_source_remove(pwrkey_long_press_timer_id),
            pwrkey_long_press_timer_id = 0;
        canceled = true;
    }
    return canceled;
}

static void
pwrkey_long_press_timer_start(void)
1619
{
1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635
    pwrkey_long_press_timer_cancel();

    pwrkey_long_press_timer_id = g_timeout_add(pwrkey_long_press_delay,
                                               pwrkey_long_press_timer_cb, 0);
}

/* ========================================================================= *
 * DOUBLE_PRESS_TIMEOUT
 * ========================================================================= */

static gboolean pwrkey_double_press_timer_cb(gpointer aptr)
{
    (void) aptr;

    if( !pwrkey_double_press_timer_id )
        goto EXIT;
1636

1637
    pwrkey_double_press_timer_id = 0;
1638

1639
    pwrkey_stm_double_press_timeout();
1640

1641
    pwrkey_stm_rethink_wakelock();
1642

1643 1644 1645
EXIT:

    return FALSE;
1646 1647
}

1648 1649
static bool
pwrkey_double_press_timer_pending(void)
1650
{
1651
    return pwrkey_double_press_timer_id != 0;
1652 1653
}

1654 1655
static bool
pwrkey_double_press_timer_cancel(void)
1656
{
1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669
    bool canceled = false;
    if( pwrkey_double_press_timer_id ) {
        g_source_remove(pwrkey_double_press_timer_id),
            pwrkey_double_press_timer_id = 0;
        canceled = true;
    }
    return canceled;
}

static void
pwrkey_double_press_timer_start(void)
{
    pwrkey_double_press_timer_cancel();
1670

1671 1672
    pwrkey_double_press_timer_id = g_timeout_add(pwrkey_double_press_delay,
                                                 pwrkey_double_press_timer_cb, 0);
1673 1674
}

1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689
/* ========================================================================= *
 * DBUS_ACTIONS
 * ========================================================================= */

static void
pwrkey_dbus_action_clear(pwrkey_dbus_action_t *self)
{
    free(self->destination), self->destination = 0;
    free(self->object),      self->object