CDC Badge OS
Firmware for the CDC Badge v1.0 hardware security key
Loading...
Searching...
No Matches
host_api_lockscreen.cpp
Go to the documentation of this file.
1
10
17#include "cdc_ui/ViewStack.h"
18#include "host_str_conv.h"
19
20#include <cstring>
21#include <string>
22
23extern "C" void* plg_get_active_plugin(void);
24
25namespace cdc::plugin_manager {
26
27namespace {
28
29constexpr size_t MAX_LOCKSCREEN_ITEMS = 8;
31
32LockscreenRegistration* slotFor(void* plugin)
33{
34 for (auto& s : s_items.slots) if (s.used && s.plugin == plugin) return &s;
35 return nullptr;
36}
37
38// Single persistent Y/N alert that overlays whatever is on screen (lock screen
39// included) and routes the answer back to the originating plugin, which may be
40// running headless in the background.
41struct AlertState {
42 cdc::ui::ConfirmView view{};
43 void* plugin = nullptr;
44 uint32_t action_id = 0;
45 bool active = false;
46};
47AlertState s_alert{};
48
49cdc::ui::ConfirmView::Icon toConfirmIcon(uint8_t icon)
50{
51 switch (icon) {
55 }
56}
57
58void onAlertResult(uint32_t answer)
59{
60 void* p = s_alert.plugin;
61 uint32_t action_id = s_alert.action_id;
62 s_alert.active = false;
63 s_alert.plugin = nullptr;
64 if (p) PluginManager::instance().dispatchActionTo(static_cast<Plugin*>(p), action_id, 0, answer);
65}
66
67void onAlertYes(void*) { onAlertResult(1); }
68void onAlertNo(void*) { onAlertResult(0); }
69
70} // namespace
71
73{
74 uint8_t n = 0;
75 for (auto& s : s_items.slots) {
76 if (!s.used) continue;
77 if (n >= max) break;
78 out[n++] = s;
79 }
80 return n;
81}
82
84{
85 if (auto* slot = slotFor(plugin)) {
86 *slot = LockscreenRegistration{};
87 }
88 // Drop ownership of a pending alert so its Y/N no longer dispatches into a
89 // plugin that is being unloaded. The modal view is static and stays valid;
90 // the user dismisses it normally and the answer is discarded.
91 if (s_alert.active && s_alert.plugin == plugin) {
92 s_alert.active = false;
93 s_alert.plugin = nullptr;
94 }
95}
96
97} // namespace cdc::plugin_manager
98
99extern "C" {
100
101int host_lockscreen_register_action(const char* label_key, uint32_t action_id)
102{
103 auto* plugin = plg_get_active_plugin();
104 if (!plugin) return HOST_ERR_NO_CAPABILITY;
105 if (!label_key) return HOST_ERR_INVALID_ARG;
106
108
109 LockscreenRegistration* slot = nullptr;
110 for (auto& s : cdc::plugin_manager::s_items.slots) {
111 if (s.used && s.plugin == plugin) { slot = &s; break; }
112 }
113 if (!slot) {
114 int slot_id = 0;
115 slot = cdc::plugin_manager::s_items.allocate(slot_id);
116 if (!slot) return HOST_ERR_NO_MEMORY;
117 }
118 slot->plugin = plugin;
119 slot->action_id = action_id;
120 std::strncpy(slot->label_key, label_key, sizeof(slot->label_key) - 1);
121 slot->label_key[sizeof(slot->label_key) - 1] = '\0';
122 slot->used = true;
123 return HOST_OK;
124}
125
127{
128 auto* plugin = plg_get_active_plugin();
129 if (!plugin) return HOST_ERR_NO_CAPABILITY;
131 return HOST_OK;
132}
133
134int host_lockscreen_alert(const char* text, uint8_t icon, uint32_t action_id)
135{
136 auto* plugin = plg_get_active_plugin();
137 if (!plugin) return HOST_ERR_NO_CAPABILITY;
138 if (!text) return HOST_ERR_INVALID_ARG;
139
140 auto& vs = cdc::ui::ViewStack::instance();
141 // Never clobber an exclusive prompt (FIDO2). Other modals are fine: the
142 // alert stacks on top and receives input until dismissed.
143 if (vs.exclusiveOwner() != nullptr) return HOST_ERR_BUSY;
144
145 std::string cp = cdc::plugin_manager::toDisplay(text);
146 cdc::plugin_manager::s_alert.plugin = plugin;
147 cdc::plugin_manager::s_alert.action_id = action_id;
148 cdc::plugin_manager::s_alert.active = true;
149 cdc::plugin_manager::s_alert.view.init(cp.c_str(),
150 cdc::plugin_manager::toConfirmIcon(icon));
151 cdc::plugin_manager::s_alert.view.setOnConfirm(&cdc::plugin_manager::onAlertYes, nullptr);
152 cdc::plugin_manager::s_alert.view.setOnCancel (&cdc::plugin_manager::onAlertNo, nullptr);
153 vs.showModal(&cdc::plugin_manager::s_alert.view);
154 vs.render();
155 return HOST_OK;
156}
157
158} // extern "C"
Internal registry of plugin lockscreen quick-actions.
Discovers, loads, runs and unloads WASM plugins on the badge.
Owned WAMR module instance + per-plugin state.
Fixed-capacity, 1-based slot table for host-API resources.
static PluginManager & instance() noexcept
void dispatchActionTo(Plugin *plugin, uint32_t action_id, uint32_t idx, uint32_t user_data)
static ViewStack & instance()
Returns singleton view-stack instance.
Definition ViewStack.cpp:34
int host_lockscreen_alert(const char *text, uint8_t icon, uint32_t action_id)
Raise a persistent Y/N alert over whatever is on screen, lock screen included, that stays until the u...
int host_lockscreen_register_action(const char *label_key, uint32_t action_id)
Publish (or replace) the plugin's lockscreen quick-action.
int host_lockscreen_unregister_action(void)
Remove the plugin's lockscreen quick-action.
#define UI_ICON_ERROR
Definition host_api.h:737
#define UI_ICON_ALERT
Definition host_api.h:754
CDC Badge OS plugin host API - canonical C ABI contract.
#define HOST_ERR_NO_CAPABILITY
Definition host_api.h:40
#define HOST_OK
Definition host_api.h:37
#define HOST_ERR_INVALID_ARG
Definition host_api.h:39
#define HOST_ERR_NO_MEMORY
Definition host_api.h:43
#define HOST_ERR_BUSY
Definition host_api.h:44
void * plg_get_active_plugin(void)
Internal UTF-8 <-> CP437 helpers for the plugin host API boundary.
std::string toDisplay(const char *utf8)
Decode a UTF-8 (with optional HTML entities) string into CP437 bytes.
uint8_t collectLockscreenItems(LockscreenRegistration *out, uint8_t max)
void clearLockscreenRegistrationFor(void *plugin)