Import of the watch repository from Pebble

This commit is contained in:
Matthieu Jeanson 2024-12-12 16:43:03 -08:00 committed by Katharine Berry
commit 3b92768480
10334 changed files with 2564465 additions and 0 deletions

279
src/fw/shell/sdk/prefs.c Normal file
View file

@ -0,0 +1,279 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "applib/preferred_content_size.h"
#include "apps/system_app_ids.h"
#include "board/board.h"
#include "os/mutex.h"
#include "process_management/app_install_manager.h"
#include "process_management/process_manager.h"
#include "services/normal/activity/activity.h"
#include "services/normal/activity/activity_insights.h"
#include "services/normal/activity/insights_settings.h"
#include "services/normal/settings/settings_file.h"
#include "shell/prefs.h"
#include "shell/prefs_private.h"
static PebbleMutex *s_mutex;
#define PREF_KEY_CLOCK_24H "clock24h"
static bool s_is_24h_style;
#define PREF_KEY_DEFAULT_WATCHFACE "watchface"
static Uuid s_default_watchface = UUID_INVALID_INIT;
#define PREF_KEY_CONTENT_SIZE "contentSize"
static uint8_t s_content_size;
#if !UNITTEST
_Static_assert(sizeof(PreferredContentSize) == sizeof(s_content_size),
"sizeof(PreferredContentSize) grew, pref needs to be migrated!");
#endif
void shell_prefs_init(void) {
s_mutex = mutex_create();
mutex_lock(s_mutex);
SettingsFile file = {};
if (settings_file_open(&file, SHELL_PREFS_FILE_NAME, SHELL_PREFS_FILE_LEN) != S_SUCCESS) {
goto cleanup;
}
if (settings_file_get(&file, PREF_KEY_CLOCK_24H, sizeof(PREF_KEY_CLOCK_24H),
&s_is_24h_style, sizeof(s_is_24h_style)) != S_SUCCESS) {
// The setting likely doesn't exist yet so set it to the default (true)
s_is_24h_style = true;
}
if (settings_file_get(&file, PREF_KEY_DEFAULT_WATCHFACE, sizeof(PREF_KEY_DEFAULT_WATCHFACE),
&s_default_watchface, sizeof(s_default_watchface)) != S_SUCCESS) {
s_default_watchface = UUID_INVALID;
}
if (settings_file_get(&file, PREF_KEY_CONTENT_SIZE, sizeof(PREF_KEY_CONTENT_SIZE),
&s_content_size, sizeof(s_content_size)) != S_SUCCESS) {
s_content_size = PreferredContentSizeDefault;
}
settings_file_close(&file);
cleanup:
mutex_unlock(s_mutex);
}
static bool prv_pref_set(const char *key, const void *val, size_t val_len) {
SettingsFile file = {};
status_t rv;
if ((rv = settings_file_open(&file, SHELL_PREFS_FILE_NAME, SHELL_PREFS_FILE_LEN)) != S_SUCCESS) {
goto cleanup;
}
rv = settings_file_set(&file, key, strnlen(key, SETTINGS_KEY_MAX_LEN) + 1, val, val_len);
settings_file_close(&file);
cleanup:
return (rv == S_SUCCESS);
}
bool shell_prefs_get_clock_24h_style(void) {
return s_is_24h_style;
}
void shell_prefs_set_clock_24h_style(bool is_24h_style) {
mutex_lock(s_mutex);
if (prv_pref_set(PREF_KEY_CLOCK_24H, &s_is_24h_style, sizeof(s_is_24h_style))) {
s_is_24h_style = is_24h_style;
}
mutex_unlock(s_mutex);
}
bool shell_prefs_is_timezone_source_manual(void) {
// Force things to automatic
return false;
}
void shell_prefs_set_timezone_source_manual(bool manual) {
}
int16_t shell_prefs_get_automatic_timezone_id(void) {
// Invalid
return -1;
}
void shell_prefs_set_automatic_timezone_id(int16_t timezone_id) {
}
// Exported function used by blob_db API to set the backing store for a specific key.
// Not used by the SDK shell
bool prefs_private_write_backing(const uint8_t *key, size_t key_len, const void *value,
int value_len) {
return false;
}
// Exported function used by blob_db API to get the length of a value in our backing store
// Not used by the SDK shell
int prefs_private_get_backing_len(const uint8_t *key, size_t key_len) {
return 0;
}
// Exported function used by blob_db API to read our backing store
// Not used by the SDK shell
bool prefs_private_read_backing(const uint8_t *key, size_t key_len, void *value, int value_len) {
return false;
}
#if CAPABILITY_HAS_SDK_SHELL4
void watchface_set_default_install_id(AppInstallId app_id) {
mutex_lock(s_mutex);
Uuid uuid;
app_install_get_uuid_for_install_id(app_id, &uuid);
if (prv_pref_set(PREF_KEY_DEFAULT_WATCHFACE, &uuid, sizeof(uuid))) {
s_default_watchface = uuid;
}
mutex_unlock(s_mutex);
}
static bool prv_set_default_any_watchface_enumerate_callback(AppInstallEntry *entry, void *data) {
if (!app_install_entry_is_watchface(entry) ||
app_install_entry_is_hidden(entry)) {
return true; // continue search
}
watchface_set_default_install_id(entry->install_id);
return false;
}
AppInstallId watchface_get_default_install_id(void) {
AppInstallId app_id = app_install_get_id_for_uuid(&s_default_watchface);
AppInstallEntry entry;
if ((app_id == INSTALL_ID_INVALID) ||
!app_install_get_entry_for_install_id(app_id, &entry) ||
!app_install_entry_is_watchface(&entry)) {
app_install_enumerate_entries(prv_set_default_any_watchface_enumerate_callback, NULL);
app_id = app_install_get_id_for_uuid(&s_default_watchface);
}
return app_id;
}
#else
AppInstallId watchface_get_default_install_id(void) {
return APP_ID_SDK;
}
void watchface_set_default_install_id(AppInstallId id) {
}
#endif
void system_theme_set_content_size(PreferredContentSize content_size) {
mutex_lock(s_mutex);
const uint8_t content_size_uint = content_size;
if (content_size >= NumPreferredContentSizes) {
PBL_LOG(LOG_LEVEL_WARNING, "Ignoring attempt to set content size to invalid size %d",
content_size);
} else if (prv_pref_set(PREF_KEY_CONTENT_SIZE, &content_size_uint, sizeof(content_size_uint))) {
s_content_size = content_size;
}
mutex_unlock(s_mutex);
}
PreferredContentSize system_theme_get_content_size(void) {
return system_theme_convert_host_content_size_to_runtime_platform(
(PreferredContentSize)s_content_size);
}
bool activity_prefs_tracking_is_enabled(void) {
#if CAPABILITY_HAS_HEALTH_TRACKING
return true;
#else
return false;
#endif
}
#if CAPABILITY_HAS_HEALTH_TRACKING
void activity_prefs_tracking_set_enabled(bool enable) {
}
bool activity_prefs_activity_insights_are_enabled(void) {
return false;
}
void activity_prefs_activity_insights_set_enabled(bool enable) {
}
bool activity_prefs_sleep_insights_are_enabled(void) {
return false;
}
void activity_prefs_sleep_insights_set_enabled(bool enable) {
}
uint8_t activity_prefs_get_health_app_opened_version(void) {
return 0;
}
void activity_prefs_set_height_mm(uint16_t height_mm) {
}
uint16_t activity_prefs_get_height_mm(void) {
return 0;
}
void activity_prefs_set_weight_dag(uint16_t weight_dag) {
}
uint16_t activity_prefs_get_weight_dag(void) {
return 0;
}
void activity_prefs_set_gender(ActivityGender gender) {
}
ActivityGender activity_prefs_get_gender(void) {
return ActivityGenderOther;
}
void activity_prefs_set_age_years(uint8_t age_years) {
}
uint8_t activity_prefs_get_age_years(void) {
return 0;
}
bool activity_prefs_heart_rate_is_enabled(void) {
return true;
}
ActivityInsightSettings *activity_prefs_get_sleep_reward_settings(void) {
static ActivityInsightSettings s_settings = { 0 };
return &s_settings;
}
void activity_prefs_set_activation_delay_insight_fired(ActivationDelayInsightType type) {
}
bool activity_prefs_has_activation_delay_insight_fired(ActivationDelayInsightType type) {
return false;
}
bool activity_prefs_get_health_app_opened(void) {
return false;
}
void activity_prefs_set_activated(void) {
}
time_t activity_prefs_get_activation_time(void) {
return 0;
}
UnitsDistance shell_prefs_get_units_distance(void) {
return UnitsDistance_Miles;
}
#endif

30
src/fw/shell/sdk/shell.c Normal file
View file

@ -0,0 +1,30 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "shell/shell.h"
#include "kernel/events.h"
#include "process_management/app_install_types.h"
const CompositorTransition* shell_get_close_compositor_animation(AppInstallId current_app_id,
AppInstallId next_app_id) {
return NULL;
}
const CompositorTransition* shell_get_open_compositor_animation(AppInstallId current_app_id,
AppInstallId next_app_id) {
return NULL;
}

View file

@ -0,0 +1,68 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "apps/system_app_ids.h"
#include "apps/system_apps/timeline/timeline.h"
#include "kernel/events.h"
#include "kernel/pbl_malloc.h"
#include "popups/notifications/notification_window.h"
#include "popups/timeline/peek.h"
#include "process_management/app_manager.h"
#include "services/common/compositor/compositor.h"
#include "services/normal/activity/activity.h"
#include "services/normal/app_inbox_service.h"
#include "services/normal/app_outbox_service.h"
#include "shell/prefs.h"
#include "shell/sdk/watchface.h"
#include "shell/shell_event_loop.h"
extern void shell_prefs_init(void);
void shell_event_loop_init(void) {
shell_prefs_init();
notification_window_service_init();
app_inbox_service_init();
app_outbox_service_init();
app_message_sender_init();
watchface_init();
timeline_peek_init();
#if CAPABILITY_HAS_HEALTH_TRACKING
// Start activity tracking if enabled
if (activity_prefs_tracking_is_enabled()) {
activity_start_tracking(false /*test_mode*/);
}
#endif
}
void shell_event_loop_handle_event(PebbleEvent *e) {
switch (e->type) {
case PEBBLE_APP_FETCH_REQUEST_EVENT:
app_manager_handle_app_fetch_request_event(&e->app_fetch_request);
return;
case PEBBLE_SYS_NOTIFICATION_EVENT:
notification_window_handle_notification(&e->sys_notification);
return;
case PEBBLE_REMINDER_EVENT:
// This handles incoming Reminders
notification_window_handle_reminder(&e->reminder);
return;
default:
break; // don't care
}
}

View file

@ -0,0 +1,33 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "shell_sdk.h"
#include "process_management/app_install_manager.h"
AppInstallId s_last_installed_app = INSTALL_ID_INVALID;
AppInstallId shell_sdk_get_last_installed_app(void) {
return s_last_installed_app;
}
void shell_sdk_set_last_installed_app(AppInstallId app_id) {
s_last_installed_app = app_id;
}
bool shell_sdk_last_installed_app_is_watchface() {
return app_install_is_watchface(shell_sdk_get_last_installed_app());
}

View file

@ -0,0 +1,28 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "process_management/app_install_types.h"
//! @file shell_sdk.h
//!
//! Hooks into system_app_state_machine.c to watch for installed apps to be launched. Latches
//! so we can figure out what was the installed app that we've launched most recently.
AppInstallId shell_sdk_get_last_installed_app(void);
void shell_sdk_set_last_installed_app(AppInstallId app_id);
bool shell_sdk_last_installed_app_is_watchface();

163
src/fw/shell/sdk/stubs.c Normal file
View file

@ -0,0 +1,163 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "drivers/backlight.h"
#include "process_management/pebble_process_md.h"
#include "services/normal/activity/activity.h"
#include "services/normal/timeline/peek.h"
#include "shell/prefs.h"
#include "util/uuid.h"
#include <stdlib.h>
void app_idle_timeout_start(void) {
}
void app_idle_timeout_refresh(void) {
}
void app_idle_timeout_stop(void) {
}
void watchface_start_low_power(bool enable) {
}
uint32_t backlight_get_timeout_ms(void) {
return DEFAULT_BACKLIGHT_TIMEOUT_MS;
}
#define SDKSHELL_BACKLIGHT_ON_PERCENT 25 // Same as snowy bb2
uint16_t backlight_get_intensity(void) {
return (BACKLIGHT_BRIGHTNESS_MAX * SDKSHELL_BACKLIGHT_ON_PERCENT / 100);
}
uint8_t backlight_get_intensity_percent(void) {
return (backlight_get_intensity() * 100) / BACKLIGHT_BRIGHTNESS_MAX;
}
void backlight_set_timeout_ms(uint32_t timeout_ms) {
}
BacklightBehaviour backlight_get_behaviour(void) {
return BacklightBehaviour_On;
}
bool backlight_is_enabled(void) {
return true;
}
bool backlight_is_ambient_sensor_enabled(void) {
return false;
}
bool backlight_is_motion_enabled(void) {
return false;
}
#include "process_management/app_install_types.h"
void worker_preferences_set_default_worker(AppInstallId id) {
}
AppInstallId worker_preferences_get_default_worker(void) {
return INSTALL_ID_INVALID;
}
#if !CAPABILITY_HAS_SDK_SHELL4
const char *app_custom_get_title(AppInstallId id) {
return NULL;
}
void customizable_app_protocol_msg_callback(void *session, const uint8_t* data,
size_t length) {
}
#endif
// Used by the alarm service to add alarm pins to the timeline
const PebbleProcessMd* alarms_app_get_info(void) {
static const PebbleProcessMdSystem s_alarms_app_info = {
.common = {
.main_func = NULL,
// UUID: 67a32d95-ef69-46d4-a0b9-854cc62f97f9
.uuid = {0x67, 0xa3, 0x2d, 0x95, 0xef, 0x69, 0x46, 0xd4,
0xa0, 0xb9, 0x85, 0x4c, 0xc6, 0x2f, 0x97, 0xf9},
},
.name = "Alarms",
};
return (const PebbleProcessMd*) &s_alarms_app_info;
}
// This stub isn't needed on tintin as it uses a different launcher
#if !PLATFORM_TINTIN && !CAPABILITY_HAS_SDK_SHELL4
#include "apps/system_apps/launcher/launcher_app.h"
const LauncherDrawState *launcher_app_get_draw_state(void) {
return NULL;
}
#endif
void analytics_external_update(void) {
}
bool shell_prefs_get_stationary_enabled(void) {
return false;
}
bool shell_prefs_get_language_english(void) {
return true;
}
void shell_prefs_set_language_english(bool english) {
}
void shell_prefs_toggle_language_english(void) {
}
void language_ui_display_changed(const char *lang_name) {
}
void timeline_peek_prefs_set_enabled(bool enabled) {}
bool timeline_peek_prefs_get_enabled(void) {
return true;
}
void timeline_peek_prefs_set_before_time(uint16_t before_time_m) {}
uint16_t timeline_peek_prefs_get_before_time(void) {
return (TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S / SECONDS_PER_MINUTE);
}
bool workout_utils_find_ongoing_activity_session(ActivitySession *session_out) {
return false;
}
uint8_t activity_prefs_heart_get_resting_hr(void) {
return 70;
}
uint8_t activity_prefs_heart_get_elevated_hr(void) {
return 100;
}
uint8_t activity_prefs_heart_get_max_hr(void) {
return 190;
}
uint8_t activity_prefs_heart_get_zone1_threshold(void) {
return 130;
}
uint8_t activity_prefs_heart_get_zone2_threshold(void) {
return 154;
}
uint8_t activity_prefs_heart_get_zone3_threshold(void) {
return 172;
}

View file

@ -0,0 +1,51 @@
{
"warning_one": [
" 1. DO NOT CHANGE OR REUSE THE ID OF ANY APPLICATION IN THE LIST ",
" 2. Read the directions "
],
"directions": [
" - The System Apps are the applications that are actually coded",
" into the firmware with static PebbleProcessMd's. ",
" - The Resource Apps are the applications that are stored in ",
" the resource pack included with the firmware. ",
" - The section 'system_apps' only lists the PebbleProcessMd* ",
" functions ",
" - Resource app entry requires a UUID, then bin_resource_id ",
" then an icon_resource_id ",
" - To enable only certain applications on a certain ",
" add the particular DEFINE variable into the 'ifdefs' field ",
" Doing so will add that application to the generated list ",
" - To disable applications entirely, add a 'DISABLED' define to",
" the list of defines for the application "
],
"warning_two": [
" 1. DO NOT CHANGE OR REUSE THE ID OF ANY APPLICATION IN THE LIST ",
" 2. Read the directions "
],
"system_apps": [
{
"id": -1,
"enum": "SDK",
"md_fn": "sdk_app_get_info"
},
{
"id": -2,
"enum": "TIMELINE",
"md_fn": "timeline_get_app_info"
},
{
"id": -3,
"enum": "LAUNCHER_MENU",
"md_fn": "launcher_menu_app_get_app_info",
"ifdefs": ["CAPABILITY_HAS_SDK_SHELL4=1"]
},
{
"id": -4,
"enum": "WATCHFACES",
"md_fn": "watchfaces_get_app_info",
"ifdefs": ["CAPABILITY_HAS_SDK_SHELL4=1"],
"color_argb8": "GColorJazzberryJamARGB8"
}
],
"resource_apps": []
}

View file

@ -0,0 +1,99 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "shell_sdk.h"
#include "apps/core_apps/panic_window_app.h"
#include "apps/sdk/sdk_app.h"
#include "apps/system_app_ids.h"
#include "apps/system_apps/launcher/launcher_app.h"
#include "kernel/panic.h"
#include "process_management/app_install_manager.h"
#include "process_management/app_manager.h"
#include "shell/system_app_state_machine.h"
#include "shell/sdk/watchface.h"
//! Whether to return to the watchface instead of the launcher upon exiting an app.
static bool s_rooted_in_watchface = false;
const PebbleProcessMd *system_app_state_machine_system_start(void) {
if (launcher_panic_get_current_error() != 0) {
return panic_app_get_app_info();
}
#if CAPABILITY_HAS_SDK_SHELL4
const AppInstallId watchface_app_id = watchface_get_default_install_id();
if (watchface_app_id != INSTALL_ID_INVALID) {
return app_install_get_md(watchface_app_id, false /* worker */);
}
#endif
return sdk_app_get_info();
}
#if CAPABILITY_HAS_SDK_SHELL4
//! @return True if the currently running app is an installed watchface
static bool prv_current_app_is_watchface(void) {
return app_install_is_watchface(app_manager_get_current_app_id());
}
AppInstallId system_app_state_machine_get_last_registered_app(void) {
// If we're rooted in the watchface but we're not the watchface itself, or the launcher
// is closing, we should launch the watchface.
if ((s_rooted_in_watchface && !prv_current_app_is_watchface()) ||
(app_manager_get_current_app_md() == launcher_menu_app_get_app_info())) {
return watchface_get_default_install_id();
}
return APP_ID_LAUNCHER_MENU;
}
const PebbleProcessMd* system_app_state_machine_get_default_app(void) {
return launcher_menu_app_get_app_info();
}
#else
AppInstallId system_app_state_machine_get_last_registered_app(void) {
return APP_ID_SDK;
}
const PebbleProcessMd* system_app_state_machine_get_default_app(void) {
return sdk_app_get_info();
}
#endif
void system_app_state_machine_register_app_launch(AppInstallId app_id) {
if (app_install_id_from_app_db(app_id)) {
shell_sdk_set_last_installed_app(app_id);
}
#if CAPABILITY_HAS_SDK_SHELL4
if (app_id == APP_ID_LAUNCHER_MENU) {
s_rooted_in_watchface = false;
} else if (app_install_is_watchface(app_id)) {
s_rooted_in_watchface = true;
}
// Other app launches don't modify our root so just ignore them.
#endif
}
void system_app_state_machine_panic(void) {
if (app_manager_is_initialized()) {
app_manager_launch_new_app(&(AppLaunchConfig) {
.md = panic_app_get_app_info(),
});
}
}

View file

@ -0,0 +1,140 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "watchface.h"
#include "applib/ui/dialogs/expandable_dialog.h"
#include "apps/system_app_ids.h"
#include "apps/system_apps/launcher/launcher_app.h"
#include "apps/system_apps/timeline/timeline.h"
#include "kernel/event_loop.h"
#include "kernel/ui/modals/modal_manager.h"
#include "popups/timeline/peek.h"
#include "process_management/app_manager.h"
#include "process_management/pebble_process_md.h"
#include "services/common/analytics/analytics.h"
#include "services/common/compositor/compositor_transitions.h"
#include "shell/sdk/shell_sdk.h"
#include "shell/system_app_state_machine.h"
#include "system/logging.h"
#include "system/passert.h"
typedef struct WatchfaceData {
ClickManager click_manager;
ButtonId button_pressed;
AppInstallId active_watchface;
} WatchfaceData;
static WatchfaceData s_watchface_data;
void watchface_launch_default(const CompositorTransition *animation) {
app_manager_put_launch_app_event(&(AppLaunchEventConfig) {
.id = watchface_get_default_install_id(),
.common.transition = animation,
});
}
static void prv_launch_app_via_button(AppLaunchEventConfig *config,
ClickRecognizerRef recognizer) {
config->common.button = click_recognizer_get_button_id(recognizer);
app_manager_put_launch_app_event(config);
}
#if CAPABILITY_HAS_SDK_SHELL4
static void prv_launch_launcher(ClickRecognizerRef recognizer, void *data) {
static const LauncherMenuArgs s_launcher_args = { .reset_scroll = true };
prv_launch_app_via_button(&(AppLaunchEventConfig) {
.id = APP_ID_LAUNCHER_MENU,
.common.args = &s_launcher_args,
}, recognizer);
}
static void prv_launch_timeline(ClickRecognizerRef recognizer, void *data) {
static TimelineArgs s_timeline_args = {
.pin_id = UUID_INVALID_INIT,
};
switch (click_recognizer_get_button_id(recognizer)) {
case BUTTON_ID_DOWN:
s_timeline_args.direction = TimelineIterDirectionFuture;
break;
case BUTTON_ID_UP:
s_timeline_args.direction = TimelineIterDirectionPast;
break;
default:
WTF;
}
prv_launch_app_via_button(&(AppLaunchEventConfig) {
.id = APP_ID_TIMELINE,
.common.args = &s_timeline_args,
}, recognizer);
}
static void prv_configure_click(ButtonId button_id, ClickHandler click_handler) {
WatchfaceData *data = &s_watchface_data;
ClickConfig *cfg = &data->click_manager.recognizers[button_id].config;
cfg->click.handler = click_handler;
}
static void prv_watchface_configure_click_handlers(void) {
prv_configure_click(BUTTON_ID_SELECT, prv_launch_launcher);
prv_configure_click(BUTTON_ID_DOWN, prv_launch_timeline);
prv_configure_click(BUTTON_ID_UP, prv_launch_timeline);
}
#endif
void watchface_init(void) {
#if CAPABILITY_HAS_SDK_SHELL4
WatchfaceData *data = &s_watchface_data;
click_manager_init(&data->click_manager);
prv_watchface_configure_click_handlers();
#endif
}
void watchface_handle_button_event(PebbleEvent *e) {
#if CAPABILITY_HAS_SDK_SHELL4
// Only handle button press if app state indicates that the app is still running
// which is not in the process of closing
WatchfaceData *data = &s_watchface_data;
if (app_manager_get_task_context()->closing_state == ProcessRunState_Running) {
data->button_pressed = e->button.button_id;
switch (e->type) {
case PEBBLE_BUTTON_DOWN_EVENT:
click_recognizer_handle_button_down(&data->click_manager.recognizers[e->button.button_id]);
break;
case PEBBLE_BUTTON_UP_EVENT:
click_recognizer_handle_button_up(&data->click_manager.recognizers[e->button.button_id]);
break;
default:
PBL_CROAK("Invalid event type: %u", e->type);
break;
}
}
#else
if ((e->button.button_id == BUTTON_ID_SELECT) && (e->type == PEBBLE_BUTTON_DOWN_EVENT)) {
app_manager_put_launch_app_event(&(AppLaunchEventConfig) {
.id = system_app_state_machine_get_last_registered_app(),
.common.reason = APP_LAUNCH_USER,
.common.button = e->button.button_id,
});
}
#endif
}
void watchface_reset_click_manager(void) {
WatchfaceData *data = &s_watchface_data;
click_manager_reset(&data->click_manager);
}

View file

@ -0,0 +1,33 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "kernel/events.h"
#include "process_management/app_install_manager.h"
#include "services/common/compositor/compositor.h"
void watchface_init(void);
void watchface_handle_button_event(PebbleEvent *e);
AppInstallId watchface_get_default_install_id(void);
void watchface_launch_default(const CompositorTransition *animation);
void watchface_set_timeline_peek_enabled(bool visible);
void watchface_reset_click_manager(void);