Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/fw/applib/ui/click.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,10 @@ void click_manager_clear(ClickManager* click_manager) {
}
}

void click_recognizer_reset(ClickRecognizer *recognizer) {
prv_click_reset(recognizer);
}

void click_manager_reset(ClickManager* click_manager) {
for (unsigned int button_id = 0; button_id < NUM_BUTTONS; button_id++) {
prv_click_reset(&click_manager->recognizers[button_id]);
Expand Down
3 changes: 3 additions & 0 deletions src/fw/applib/ui/click_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ void click_recognizer_handle_button_up(ClickRecognizer *recognizer);
//! Tell the particular recognizer that the associated button has been pressed.
void click_recognizer_handle_button_down(ClickRecognizer *recognizer);

//! Reset the state of a single recognizer, including timers.
void click_recognizer_reset(ClickRecognizer *recognizer);

//! Initialize a click manager for use. This only needs to be called once to initialize the structure, and then the
//! same struct can be reconfigured multiple times by using click_manager_clear.
void click_manager_init(ClickManager* click_manager);
Expand Down
1 change: 1 addition & 0 deletions src/fw/services/normal/blob_db/settings_blob_db.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ static const char *s_syncable_settings[] = {
"qlSetupOpened",
"qlSingleClickUp",
"qlSingleClickDown",
"qlComboBackUp",

// UI theming
"settingsMenuHighlightColor",
Expand Down
34 changes: 34 additions & 0 deletions src/fw/shell/normal/prefs.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ static QuickLaunchPreference s_quick_launch_back = {

#define PREF_KEY_QUICK_LAUNCH_SINGLE_CLICK_UP "qlSingleClickUp"
#define PREF_KEY_QUICK_LAUNCH_SINGLE_CLICK_DOWN "qlSingleClickDown"
#define PREF_KEY_QUICK_LAUNCH_COMBO_BACK_UP "qlComboBackUp"

static QuickLaunchPreference s_quick_launch_single_click_up = {
.enabled = true,
Expand All @@ -154,6 +155,11 @@ static QuickLaunchPreference s_quick_launch_single_click_down = {
.uuid = TIMELINE_UUID_INIT,
};

static QuickLaunchPreference s_quick_launch_combo_back_up = {
.enabled = false,
.uuid = UUID_INVALID_INIT,
};

#define PREF_KEY_QUICK_LAUNCH_SETUP_OPENED "qlSetupOpened"
static uint8_t s_quick_launch_setup_opened = 0;

Expand Down Expand Up @@ -427,6 +433,12 @@ static bool prv_set_s_quick_launch_single_click_down(QuickLaunchPreference *pref
return true;
}

static bool prv_set_s_quick_launch_combo_back_up(QuickLaunchPreference *pref) {
prv_normalize_quick_launch_pref(pref);
s_quick_launch_combo_back_up = *pref;
return true;
}

static bool prv_set_s_quick_launch_setup_opened(uint8_t *version) {
s_quick_launch_setup_opened = *version;
return true;
Expand Down Expand Up @@ -1318,6 +1330,28 @@ void quick_launch_single_click_set_enabled(ButtonId button, bool enabled) {
prv_pref_set(key, &pref, sizeof(pref));
}

bool quick_launch_combo_back_up_is_enabled(void) {
return s_quick_launch_combo_back_up.enabled;
}

AppInstallId quick_launch_combo_back_up_get_app(void) {
return app_install_get_id_for_uuid(&s_quick_launch_combo_back_up.uuid);
}

void quick_launch_combo_back_up_set_app(AppInstallId app_id) {
QuickLaunchPreference pref = (QuickLaunchPreference) {
.enabled = true,
Comment thread
jplexer marked this conversation as resolved.
};
app_install_get_uuid_for_install_id(app_id, &pref.uuid);
prv_pref_set(PREF_KEY_QUICK_LAUNCH_COMBO_BACK_UP, &pref, sizeof(pref));
}

void quick_launch_combo_back_up_set_enabled(bool enabled) {
QuickLaunchPreference pref = s_quick_launch_combo_back_up;
pref.enabled = enabled;
prv_pref_set(PREF_KEY_QUICK_LAUNCH_COMBO_BACK_UP, &pref, sizeof(pref));
}

void watchface_set_default_install_id(AppInstallId app_id) {
Uuid uuid;
app_install_get_uuid_for_install_id(app_id, &uuid);
Expand Down
1 change: 1 addition & 0 deletions src/fw/shell/normal/prefs_values.h.inc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
PREFS_MACRO(PREF_KEY_QUICK_LAUNCH_BACK, s_quick_launch_back)
PREFS_MACRO(PREF_KEY_QUICK_LAUNCH_SINGLE_CLICK_UP, s_quick_launch_single_click_up)
PREFS_MACRO(PREF_KEY_QUICK_LAUNCH_SINGLE_CLICK_DOWN, s_quick_launch_single_click_down)
PREFS_MACRO(PREF_KEY_QUICK_LAUNCH_COMBO_BACK_UP, s_quick_launch_combo_back_up)
PREFS_MACRO(PREF_KEY_QUICK_LAUNCH_SETUP_OPENED, s_quick_launch_setup_opened)
PREFS_MACRO(PREF_KEY_DEFAULT_WATCHFACE, s_default_watchface)
PREFS_MACRO(PREF_KEY_WELCOME_VERSION, s_welcome_version)
Expand Down
5 changes: 5 additions & 0 deletions src/fw/shell/normal/quick_launch.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,8 @@ bool quick_launch_single_click_is_enabled(ButtonId button);
AppInstallId quick_launch_single_click_get_app(ButtonId button);
void quick_launch_single_click_set_app(ButtonId button, AppInstallId app_id);
void quick_launch_single_click_set_enabled(ButtonId button, bool enabled);

bool quick_launch_combo_back_up_is_enabled(void);
AppInstallId quick_launch_combo_back_up_get_app(void);
void quick_launch_combo_back_up_set_app(AppInstallId app_id);
void quick_launch_combo_back_up_set_enabled(bool enabled);
74 changes: 71 additions & 3 deletions src/fw/shell/normal/watchface.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,20 @@
#include "process_management/pebble_process_md.h"
#include "services/common/analytics/analytics.h"
#include "services/common/compositor/compositor_transitions.h"
#include "applib/app_timer.h"
#include "applib/ui/click_internal.h"
#include "services/normal/notifications/do_not_disturb.h"
#include "system/logging.h"
#include "system/passert.h"

#define QUICK_LAUNCH_HOLD_MS (400)
#define BIT_SET (1)
#define BIT_CLEAR (0)
#define COMBO_BACK_UP_BUTTONS ((BIT_SET << BUTTON_ID_BACK) | (BIT_SET << BUTTON_ID_UP))

static ClickManager s_click_manager;
static uint8_t s_buttons_pressed = BIT_CLEAR;
static AppTimer *s_combo_back_up_timer = NULL;

static bool prv_should_ignore_button_click(void) {
if (app_manager_get_task_context()->closing_state != ProcessRunState_Running) {
Expand All @@ -44,28 +51,82 @@ static void prv_launch_app_via_button(AppLaunchEventConfig *config,
app_manager_put_launch_app_event(config);
}

static void prv_combo_back_up_timer_callback(void *data) {
s_combo_back_up_timer = NULL;
// Double-check that both buttons are still pressed before executing combo
if ((s_buttons_pressed & COMBO_BACK_UP_BUTTONS) == COMBO_BACK_UP_BUTTONS) {
if (quick_launch_combo_back_up_is_enabled()) {
AppInstallId app_id = quick_launch_combo_back_up_get_app();
if (app_id != INSTALL_ID_INVALID) {
// Reset all button states before launching app to prevent state corruption
s_buttons_pressed = BIT_CLEAR; // Reset our own tracking
app_manager_put_launch_app_event(&(AppLaunchEventConfig) {
.id = app_id,
.common.reason = APP_LAUNCH_QUICK_LAUNCH,
.common.button = BUTTON_ID_BACK,
});
return;
}
}
}
}

static void prv_check_combo_back_up(void) {
bool back_pressed = (s_buttons_pressed & (BIT_SET << BUTTON_ID_BACK)) != BIT_CLEAR;
bool up_pressed = (s_buttons_pressed & (BIT_SET << BUTTON_ID_UP)) != BIT_CLEAR;
bool both_pressed = back_pressed && up_pressed;

if (both_pressed) {
if (s_combo_back_up_timer == NULL) {
// Cancel individual button timers to prevent them from firing
// This ensures only the combo executes, not individual hold handlers
click_recognizer_reset(&s_click_manager.recognizers[BUTTON_ID_BACK]);
click_recognizer_reset(&s_click_manager.recognizers[BUTTON_ID_UP]);
s_combo_back_up_timer = app_timer_register(QUICK_LAUNCH_HOLD_MS, prv_combo_back_up_timer_callback, NULL);
}
} else {
if (s_combo_back_up_timer != NULL) {
app_timer_cancel(s_combo_back_up_timer);
s_combo_back_up_timer = NULL;
}
}
}

static void prv_quick_launch_handler(ClickRecognizerRef recognizer, void *data) {
ButtonId button = click_recognizer_get_button_id(recognizer);

if (s_combo_back_up_timer != NULL ||
(s_buttons_pressed & COMBO_BACK_UP_BUTTONS) == COMBO_BACK_UP_BUTTONS) {
return;
}

if (!quick_launch_is_enabled(button)) {
return;
}
AppInstallId app_id = quick_launch_get_app(button);
if (app_id == INSTALL_ID_INVALID) {
app_id = app_install_get_id_for_uuid(&quick_launch_setup_get_app_info()->uuid);
}
s_buttons_pressed = BIT_CLEAR; // Reset our own tracking
prv_launch_app_via_button(&(AppLaunchEventConfig) {
.id = app_id,
.common.reason = APP_LAUNCH_QUICK_LAUNCH,
}, recognizer);
}

static void prv_launch_up_down(ClickRecognizerRef recognizer, void *data) {
if (!quick_launch_single_click_is_enabled(click_recognizer_get_button_id(recognizer))) return;
ButtonId button = click_recognizer_get_button_id(recognizer);

if ((s_buttons_pressed & COMBO_BACK_UP_BUTTONS) == COMBO_BACK_UP_BUTTONS) {
return;
}

if (!quick_launch_single_click_is_enabled(button)) return;
//check if quick launch app is not timeline
if (quick_launch_single_click_get_app(click_recognizer_get_button_id(recognizer)) != APP_ID_TIMELINE) {
if (quick_launch_single_click_get_app(button) != APP_ID_TIMELINE) {
//launch other quick launch apps
prv_launch_app_via_button(&(AppLaunchEventConfig) {
.id = quick_launch_single_click_get_app(click_recognizer_get_button_id(recognizer)),
.id = quick_launch_single_click_get_app(button),
.common.reason = APP_LAUNCH_QUICK_LAUNCH,
}, recognizer);
return;
Expand Down Expand Up @@ -120,6 +181,9 @@ static void prv_launch_launcher_app(ClickRecognizerRef recognizer, void *data) {
}

static void prv_dismiss_timeline_peek(ClickRecognizerRef recognizer, void *data) {
if ((s_buttons_pressed & COMBO_BACK_UP_BUTTONS) == COMBO_BACK_UP_BUTTONS) {
return;
}
timeline_peek_dismiss();
}

Expand All @@ -141,9 +205,13 @@ void watchface_handle_button_event(PebbleEvent *e) {
}
switch (e->type) {
case PEBBLE_BUTTON_DOWN_EVENT:
s_buttons_pressed |= (BIT_SET << e->button.button_id);
click_recognizer_handle_button_down(&s_click_manager.recognizers[e->button.button_id]);
prv_check_combo_back_up();
break;
case PEBBLE_BUTTON_UP_EVENT:
s_buttons_pressed &= ~(BIT_SET << e->button.button_id);
prv_check_combo_back_up();
click_recognizer_handle_button_up(&s_click_manager.recognizers[e->button.button_id]);
break;
default:
Expand Down
Loading