Skip to content

Commit

Permalink
[powerkey] Add "vibrate" power key action. Contribues to JB#24488
Browse files Browse the repository at this point in the history
It is difficult to tell whether single or double power key press
gets executed when display turns off.

Add "vibrate" action that can be used for example to provide tactile
feedback when double power key press gets executed.
  • Loading branch information
spiiroin committed Sep 10, 2015
1 parent 19284b2 commit 1b539e5
Show file tree
Hide file tree
Showing 7 changed files with 230 additions and 6 deletions.
1 change: 1 addition & 0 deletions Makefile
Expand Up @@ -261,6 +261,7 @@ MCE_PKG_NAMES += dbus-glib-1
MCE_PKG_NAMES += dsme
MCE_PKG_NAMES += libiphb
MCE_PKG_NAMES += libsystemd-daemon
MCE_PKG_NAMES += libngf0

MCE_PKG_CFLAGS := $(shell $(PKG_CONFIG) --cflags $(MCE_PKG_NAMES))
MCE_PKG_LDLIBS := $(shell $(PKG_CONFIG) --libs $(MCE_PKG_NAMES))
Expand Down
6 changes: 6 additions & 0 deletions datapipe.c
Expand Up @@ -175,6 +175,9 @@ datapipe_struct lipstick_available_pipe;
/** usbmoded availability; read only */
datapipe_struct usbmoded_available_pipe;

/** ngfd availability; read only */
datapipe_struct ngfd_available_pipe;

/** dsme availability; read only */
datapipe_struct dsme_available_pipe;

Expand Down Expand Up @@ -896,6 +899,8 @@ void mce_datapipe_init(void)
0, GINT_TO_POINTER(SERVICE_STATE_UNDEF));
setup_datapipe(&usbmoded_available_pipe, READ_ONLY, DONT_FREE_CACHE,
0, GINT_TO_POINTER(SERVICE_STATE_UNDEF));
setup_datapipe(&ngfd_available_pipe, READ_ONLY, DONT_FREE_CACHE,
0, GINT_TO_POINTER(SERVICE_STATE_UNDEF));

setup_datapipe(&dsme_available_pipe, READ_ONLY, DONT_FREE_CACHE,
0, GINT_TO_POINTER(SERVICE_STATE_UNDEF));
Expand Down Expand Up @@ -973,6 +978,7 @@ void mce_datapipe_quit(void)
free_datapipe(&compositor_available_pipe);
free_datapipe(&lipstick_available_pipe);
free_datapipe(&usbmoded_available_pipe);
free_datapipe(&ngfd_available_pipe);
free_datapipe(&dsme_available_pipe);
free_datapipe(&packagekit_locked_pipe);
free_datapipe(&update_mode_pipe);
Expand Down
1 change: 1 addition & 0 deletions datapipe.h
Expand Up @@ -137,6 +137,7 @@ extern datapipe_struct heartbeat_pipe;
extern datapipe_struct compositor_available_pipe;
extern datapipe_struct lipstick_available_pipe;
extern datapipe_struct usbmoded_available_pipe;
extern datapipe_struct ngfd_available_pipe;
extern datapipe_struct dsme_available_pipe;
extern datapipe_struct packagekit_locked_pipe;
extern datapipe_struct update_mode_pipe;
Expand Down
4 changes: 4 additions & 0 deletions mce-dbus.c
Expand Up @@ -3297,6 +3297,10 @@ static struct
.name = USB_MODED_DBUS_SERVICE,
.datapipe = &usbmoded_available_pipe,
},
{
.name = "com.nokia.NonGraphicFeedback1.Backend",
.datapipe = &ngfd_available_pipe,
},
{
.name = 0,
}
Expand Down
215 changes: 210 additions & 5 deletions powerkey.c
Expand Up @@ -3,7 +3,7 @@
* Power key logic for the Mode Control Entity
* <p>
* Copyright © 2004-2011 Nokia Corporation and/or its subsidiary(-ies).
* Copyright © 2014 Jolla Ltd.
* Copyright © 2014-2015 Jolla Ltd.
* <p>
* @author David Weinehall <david.weinehall@nokia.com>
* @author Simo Piiroinen <simo.piiroinen@jollamobile.com>
Expand Down Expand Up @@ -45,6 +45,8 @@

#include <mce/dbus-names.h>

#include <libngf/ngf.h>

/* ========================================================================= *
* OVERVIEW
*
Expand Down Expand Up @@ -143,6 +145,7 @@ static void pwrkey_ps_override_evaluate(void);
static gint pwrkey_action_blank_mode = PWRKEY_BLANK_TO_OFF;
static guint pwrkey_action_blank_mode_gconf_id = 0;

static void pwrkey_action_vibrate (void);
static void pwrkey_action_shutdown (void);
static void pwrkey_action_tklock (void);
static void pwrkey_action_blank (void);
Expand Down Expand Up @@ -263,6 +266,18 @@ static bool pwrkey_double_press_timer_pending(void);
static bool pwrkey_double_press_timer_cancel(void);
static void pwrkey_double_press_timer_start(void);

/* ------------------------------------------------------------------------- *
* 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);

/* ------------------------------------------------------------------------- *
* DBUS_ACTIONS
*
Expand Down Expand Up @@ -410,6 +425,7 @@ static void pwrkey_gconf_quit(void);
* ------------------------------------------------------------------------- */

static void pwrkey_datapipes_keypress_cb(gconstpointer const data);
static void pwrkey_datapipe_ngfd_available_cb(gconstpointer data);

static void pwrkey_datapipes_init(void);
static void pwrkey_datapipes_quit(void);
Expand Down Expand Up @@ -601,6 +617,13 @@ pwrkey_ps_override_evaluate(void)
* ACTION_EXEC
* ========================================================================= */

static void
pwrkey_action_vibrate(void)
{
mce_log(LL_DEBUG, "Requesting vibrate");
xngf_play_event("pwrkey");
}

static void
pwrkey_action_shutdown(void)
{
Expand Down Expand Up @@ -768,6 +791,10 @@ static const pwrkey_bitconf_t pwrkey_action_lut[] =
.name = "shutdown",
.func = pwrkey_action_shutdown,
},
{
.name = "vibrate",
.func = pwrkey_action_vibrate,
},

// Direction: OFF->ON
{
Expand Down Expand Up @@ -2168,6 +2195,33 @@ pwrkey_gconf_quit(void)
* DATAPIPE_HANDLING
* ========================================================================= */

/** NGFD availability */
static service_state_t ngfd_available = SERVICE_STATE_UNDEF;

/** Handle ngfd_available notifications
*
* @param data service availability (as void pointer)
*/
static void
pwrkey_datapipe_ngfd_available_cb(gconstpointer data)
{
service_state_t prev = ngfd_available;
ngfd_available = GPOINTER_TO_INT(data);

if( ngfd_available == prev )
goto EXIT;

mce_log(LL_NOTICE, "ngfd_available = %s -> %s",
service_state_repr(prev),
service_state_repr(ngfd_available));

if( ngfd_available != SERVICE_STATE_RUNNING )
xngf_delete_client();

EXIT:
return;
}

/**
* Datapipe trigger for the [power] key
*
Expand Down Expand Up @@ -2214,22 +2268,169 @@ pwrkey_datapipes_keypress_cb(gconstpointer const data)
return;
}

/** Array of datapipe handlers */
static datapipe_handler_t pwrkey_datapipe_handlers[] =
{
// input triggers
{
.datapipe = &keypress_pipe,
.input_cb = pwrkey_datapipes_keypress_cb,
},
// output triggers
{
.datapipe = &ngfd_available_pipe,
.output_cb = pwrkey_datapipe_ngfd_available_cb,
},
// sentinel
{
.datapipe = 0,
}
};

static datapipe_bindings_t pwrkey_datapipe_bindings =
{
.module = "powerkey",
.handlers = pwrkey_datapipe_handlers,
};

/** Append triggers/filters to datapipes
*/
static void
pwrkey_datapipes_init(void)
{
append_input_trigger_to_datapipe(&keypress_pipe,
pwrkey_datapipes_keypress_cb);
datapipe_bindings_init(&pwrkey_datapipe_bindings);
}

/** Remove triggers/filters from datapipes
*/
static void
pwrkey_datapipes_quit(void)
{
remove_input_trigger_from_datapipe(&keypress_pipe,
pwrkey_datapipes_keypress_cb);
datapipe_bindings_quit(&pwrkey_datapipe_bindings);
}

/* ========================================================================= *
* NGFD_GLUE
* ========================================================================= */

static NgfClient *ngf_client_hnd = 0;
static DBusConnection *ngf_dbus_con = 0;
static uint32_t ngf_event_id = 0;

static const char *
xngf_state_repr(NgfEventState state)
{
const char *repr = "unknown";

switch( state ) {
case NGF_EVENT_FAILED: repr = "failed"; break;
case NGF_EVENT_COMPLETED: repr = "completed"; break;
case NGF_EVENT_PLAYING: repr = "playing"; break;
case NGF_EVENT_PAUSED: repr = "paused"; break;
default: break;
}

return repr;
}
static void
xngf_status_cb(NgfClient *client, uint32_t event_id, NgfEventState state, void *userdata)
{
(void) client;
(void) userdata;

mce_log(LL_DEBUG, "%s(%d)", xngf_state_repr(state), event_id);

switch( state ) {
default:
case NGF_EVENT_PLAYING:
case NGF_EVENT_PAUSED:
break;

case NGF_EVENT_COMPLETED:
ngf_event_id = 0;
break;

case NGF_EVENT_FAILED:
mce_log(LL_ERR, "Failed to play id %d", event_id);
ngf_event_id = 0;
break;

}
}

static bool
xngf_create_client(void)
{
if( !ngf_dbus_con ) {
mce_log(LL_WARN, "can't use ngfd - no dbus connection");
goto EXIT;
}

if( ngfd_available != SERVICE_STATE_RUNNING ) {
mce_log(LL_WARN, "can't use ngfd - service not running");
goto EXIT;
}

if( ngf_client_hnd )
goto EXIT;

ngf_client_hnd = ngf_client_create(NGF_TRANSPORT_DBUS, ngf_dbus_con);
if( !ngf_client_hnd ) {
mce_log(LL_WARN, "can't use ngfd - failed to create client");
goto EXIT;
}

ngf_client_set_callback(ngf_client_hnd, xngf_status_cb, NULL);

mce_log(LL_DEBUG, "ngfd client created");

EXIT:
return ngf_client_hnd != 0;
}

static void
xngf_delete_client(void)
{
if( ngf_client_hnd ) {
ngf_client_destroy(ngf_client_hnd), ngf_client_hnd = 0;
mce_log(LL_DEBUG, "ngfd client deleted");
}

ngf_event_id = 0;
}

static void
xngf_play_event(const char *event_name)
{
if( ngf_event_id ) {
mce_log(LL_WARN, "previous event not finished yet");
goto EXIT;
}

if( !xngf_create_client() )
goto EXIT;

ngf_event_id = ngf_client_play_event (ngf_client_hnd, event_name, NULL);

mce_log(LL_DEBUG, "event=%s, id=%d", event_name, ngf_event_id);

EXIT:
return;
}

static void
xngf_init(void)
{
ngf_dbus_con = dbus_connection_get();
}

static void
xngf_quit(void)
{
xngf_delete_client();

if (ngf_dbus_con)
dbus_connection_unref(ngf_dbus_con), ngf_dbus_con = 0;
}

/* ========================================================================= *
Expand All @@ -2249,6 +2450,8 @@ gboolean mce_powerkey_init(void)

pwrkey_gconf_init();

xngf_init();

return TRUE;
}

Expand All @@ -2259,6 +2462,8 @@ gboolean mce_powerkey_init(void)
*/
void mce_powerkey_exit(void)
{
xngf_quit();

pwrkey_dbus_quit();

pwrkey_gconf_quit();
Expand Down
1 change: 1 addition & 0 deletions rpm/mce.spec
Expand Up @@ -20,6 +20,7 @@ BuildRequires: pkgconfig(dsme) >= 0.58
BuildRequires: pkgconfig(libiphb)
BuildRequires: pkgconfig(glib-2.0) >= 2.36.0
BuildRequires: pkgconfig(mce) >= 1.17.0
BuildRequires: pkgconfig(libngf0) >= 0.24
BuildRequires: pkgconfig(libsystemd-daemon)
BuildRequires: kernel-headers >= 2.6.32
BuildRequires: systemd
Expand Down
8 changes: 7 additions & 1 deletion tools/mcetool.c
Expand Up @@ -3526,6 +3526,7 @@ static bool xmce_is_powerkey_action(const char *name)
"tklock",
"devlock",
"shutdown",
"vibrate",
"unblank",
"tkunlock",
"dbus1",
Expand Down Expand Up @@ -5192,11 +5193,16 @@ static const mce_opt_t options[] =
" blank - turn display off\n"
" tklock - lock ui\n"
" devlock - lock device\n"
" dbus1 - send dbus signal or make method call\n"
" shutdown - power off device\n"
" vibrate - play vibrate event via ngfd\n"
" unblank - turn display on\n"
" tkunlock - unlock ui\n"
" dbus1 - send dbus signal or make method call\n"
" dbus2 - send dbus signal or make method call\n"
" dbus3 - send dbus signal or make method call\n"
" dbus4 - send dbus signal or make method call\n"
" dbus5 - send dbus signal or make method call\n"
" dbus6 - send dbus signal or make method call\n"
"\n"
"Comma separated list of actions can be used.\n"
},
Expand Down

0 comments on commit 1b539e5

Please sign in to comment.