[FL-2430] Automatic Desktop Locking (#1101)
* Add Auto Lock Time setting * Update .gitignore * Add value_index toolbox module * Auto locking basic implementation * Better AutoLock implementation, edge cases and cleanup * Fix NULL pointer crash * Turn off backlight shortly in locked mode * Re-enable auto lock after pin lock * Correctly handle start when pin locked * Use timer to hide locked hint * Use a single state variable instead of multiple bools * Do not call update callback recursively * Allow input when the Unlocked hint is shown * Add a delay to backlight switch off while locking * Better user input handling * Switch backlight off after pin timeout * Correct grammar in notification settings Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
parent
779d319069
commit
917be9c6d3
3
.gitignore
vendored
3
.gitignore
vendored
@ -36,3 +36,6 @@ CMakeLists.txt
|
|||||||
|
|
||||||
# bundle output
|
# bundle output
|
||||||
dist
|
dist
|
||||||
|
|
||||||
|
# kde
|
||||||
|
.directory
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
#include <storage/storage.h>
|
#include <storage/storage.h>
|
||||||
#include <assets_icons.h>
|
#include <assets_icons.h>
|
||||||
|
#include <gui/gui.h>
|
||||||
#include <gui/view_stack.h>
|
#include <gui/view_stack.h>
|
||||||
|
#include <notification/notification.h>
|
||||||
|
#include <notification/notification_messages.h>
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <furi_hal.h>
|
#include <furi_hal.h>
|
||||||
|
|
||||||
@ -13,6 +16,10 @@
|
|||||||
#include "desktop_i.h"
|
#include "desktop_i.h"
|
||||||
#include "desktop_helpers.h"
|
#include "desktop_helpers.h"
|
||||||
|
|
||||||
|
static void desktop_auto_lock_arm(Desktop*);
|
||||||
|
static void desktop_auto_lock_inhibit(Desktop*);
|
||||||
|
static void desktop_start_auto_lock_timer(Desktop*);
|
||||||
|
|
||||||
static void desktop_loader_callback(const void* message, void* context) {
|
static void desktop_loader_callback(const void* message, void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
Desktop* desktop = context;
|
Desktop* desktop = context;
|
||||||
@ -37,9 +44,19 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) {
|
|||||||
switch(event) {
|
switch(event) {
|
||||||
case DesktopGlobalBeforeAppStarted:
|
case DesktopGlobalBeforeAppStarted:
|
||||||
animation_manager_unload_and_stall_animation(desktop->animation_manager);
|
animation_manager_unload_and_stall_animation(desktop->animation_manager);
|
||||||
|
desktop_auto_lock_inhibit(desktop);
|
||||||
return true;
|
return true;
|
||||||
case DesktopGlobalAfterAppFinished:
|
case DesktopGlobalAfterAppFinished:
|
||||||
animation_manager_load_and_continue_animation(desktop->animation_manager);
|
animation_manager_load_and_continue_animation(desktop->animation_manager);
|
||||||
|
// TODO: Implement a message mechanism for loading settings and (optionally)
|
||||||
|
// locking and unlocking
|
||||||
|
LOAD_DESKTOP_SETTINGS(&desktop->settings);
|
||||||
|
desktop_auto_lock_arm(desktop);
|
||||||
|
return true;
|
||||||
|
case DesktopGlobalAutoLock:
|
||||||
|
if(!loader_is_locked(desktop->loader)) {
|
||||||
|
desktop_lock(desktop);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +75,63 @@ static void desktop_tick_event_callback(void* context) {
|
|||||||
scene_manager_handle_tick_event(app->scene_manager);
|
scene_manager_handle_tick_event(app->scene_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void desktop_input_event_callback(const void* value, void* context) {
|
||||||
|
furi_assert(value);
|
||||||
|
furi_assert(context);
|
||||||
|
const InputEvent* event = value;
|
||||||
|
Desktop* desktop = context;
|
||||||
|
if(event->type == InputTypePress) {
|
||||||
|
desktop_start_auto_lock_timer(desktop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void desktop_auto_lock_timer_callback(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
Desktop* desktop = context;
|
||||||
|
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalAutoLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void desktop_start_auto_lock_timer(Desktop* desktop) {
|
||||||
|
osTimerStart(
|
||||||
|
desktop->auto_lock_timer, furi_hal_ms_to_ticks(desktop->settings.auto_lock_delay_ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void desktop_stop_auto_lock_timer(Desktop* desktop) {
|
||||||
|
osTimerStop(desktop->auto_lock_timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void desktop_auto_lock_arm(Desktop* desktop) {
|
||||||
|
if(desktop->settings.auto_lock_delay_ms) {
|
||||||
|
desktop->input_events_subscription = furi_pubsub_subscribe(
|
||||||
|
desktop->input_events_pubsub, desktop_input_event_callback, desktop);
|
||||||
|
desktop_start_auto_lock_timer(desktop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void desktop_auto_lock_inhibit(Desktop* desktop) {
|
||||||
|
desktop_stop_auto_lock_timer(desktop);
|
||||||
|
if(desktop->input_events_subscription) {
|
||||||
|
furi_pubsub_unsubscribe(desktop->input_events_pubsub, desktop->input_events_subscription);
|
||||||
|
desktop->input_events_subscription = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void desktop_lock(Desktop* desktop) {
|
||||||
|
desktop_auto_lock_inhibit(desktop);
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER);
|
||||||
|
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked);
|
||||||
|
notification_message(desktop->notification, &sequence_display_off_delay_1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void desktop_unlock(Desktop* desktop) {
|
||||||
|
furi_hal_rtc_set_pin_fails(0);
|
||||||
|
desktop_helpers_unlock_system(desktop);
|
||||||
|
desktop_view_locked_unlock(desktop->locked_view);
|
||||||
|
scene_manager_search_and_switch_to_previous_scene(desktop->scene_manager, DesktopSceneMain);
|
||||||
|
desktop_auto_lock_arm(desktop);
|
||||||
|
}
|
||||||
|
|
||||||
Desktop* desktop_alloc() {
|
Desktop* desktop_alloc() {
|
||||||
Desktop* desktop = malloc(sizeof(Desktop));
|
Desktop* desktop = malloc(sizeof(Desktop));
|
||||||
|
|
||||||
@ -146,9 +220,17 @@ Desktop* desktop_alloc() {
|
|||||||
animation_manager_is_animation_loaded(desktop->animation_manager)) {
|
animation_manager_is_animation_loaded(desktop->animation_manager)) {
|
||||||
animation_manager_unload_and_stall_animation(desktop->animation_manager);
|
animation_manager_unload_and_stall_animation(desktop->animation_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
desktop->notification = furi_record_open("notification");
|
||||||
desktop->app_start_stop_subscription = furi_pubsub_subscribe(
|
desktop->app_start_stop_subscription = furi_pubsub_subscribe(
|
||||||
loader_get_pubsub(desktop->loader), desktop_loader_callback, desktop);
|
loader_get_pubsub(desktop->loader), desktop_loader_callback, desktop);
|
||||||
|
|
||||||
|
desktop->input_events_pubsub = furi_record_open("input_events");
|
||||||
|
desktop->input_events_subscription = NULL;
|
||||||
|
|
||||||
|
desktop->auto_lock_timer =
|
||||||
|
osTimerNew(desktop_auto_lock_timer_callback, osTimerOnce, desktop, NULL);
|
||||||
|
|
||||||
return desktop;
|
return desktop;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,8 +239,17 @@ void desktop_free(Desktop* desktop) {
|
|||||||
|
|
||||||
furi_pubsub_unsubscribe(
|
furi_pubsub_unsubscribe(
|
||||||
loader_get_pubsub(desktop->loader), desktop->app_start_stop_subscription);
|
loader_get_pubsub(desktop->loader), desktop->app_start_stop_subscription);
|
||||||
|
|
||||||
|
if(desktop->input_events_subscription) {
|
||||||
|
furi_pubsub_unsubscribe(desktop->input_events_pubsub, desktop->input_events_subscription);
|
||||||
|
desktop->input_events_subscription = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
desktop->loader = NULL;
|
desktop->loader = NULL;
|
||||||
|
desktop->input_events_pubsub = NULL;
|
||||||
furi_record_close("loader");
|
furi_record_close("loader");
|
||||||
|
furi_record_close("notification");
|
||||||
|
furi_record_close("input_events");
|
||||||
|
|
||||||
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdMain);
|
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdMain);
|
||||||
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLockMenu);
|
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLockMenu);
|
||||||
@ -191,6 +282,8 @@ void desktop_free(Desktop* desktop) {
|
|||||||
|
|
||||||
furi_record_close("menu");
|
furi_record_close("menu");
|
||||||
|
|
||||||
|
osTimerDelete(desktop->auto_lock_timer);
|
||||||
|
|
||||||
free(desktop);
|
free(desktop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,14 +307,16 @@ int32_t desktop_srv(void* p) {
|
|||||||
|
|
||||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain);
|
scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain);
|
||||||
|
|
||||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) {
|
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock) && !desktop->settings.pin_code.length) {
|
||||||
if(desktop->settings.pin_code.length > 0) {
|
furi_hal_rtc_reset_flag(FuriHalRtcFlagLock);
|
||||||
scene_manager_set_scene_state(
|
}
|
||||||
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER);
|
|
||||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked);
|
if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) {
|
||||||
} else {
|
if(!loader_is_locked(desktop->loader)) {
|
||||||
furi_hal_rtc_reset_flag(FuriHalRtcFlagLock);
|
desktop_auto_lock_arm(desktop);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
desktop_lock(desktop);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(desktop_is_first_start()) {
|
if(desktop_is_first_start()) {
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <gui/scene_manager.h>
|
#include <gui/scene_manager.h>
|
||||||
|
|
||||||
#include <loader/loader.h>
|
#include <loader/loader.h>
|
||||||
|
#include <notification/notification_app.h>
|
||||||
|
|
||||||
#define STATUS_BAR_Y_SHIFT 13
|
#define STATUS_BAR_Y_SHIFT 13
|
||||||
|
|
||||||
@ -59,10 +60,18 @@ struct Desktop {
|
|||||||
ViewPort* lock_viewport;
|
ViewPort* lock_viewport;
|
||||||
|
|
||||||
AnimationManager* animation_manager;
|
AnimationManager* animation_manager;
|
||||||
|
|
||||||
Loader* loader;
|
Loader* loader;
|
||||||
|
NotificationApp* notification;
|
||||||
|
|
||||||
FuriPubSubSubscription* app_start_stop_subscription;
|
FuriPubSubSubscription* app_start_stop_subscription;
|
||||||
|
FuriPubSub* input_events_pubsub;
|
||||||
|
FuriPubSubSubscription* input_events_subscription;
|
||||||
|
osTimerId_t auto_lock_timer;
|
||||||
};
|
};
|
||||||
|
|
||||||
Desktop* desktop_alloc();
|
Desktop* desktop_alloc();
|
||||||
|
|
||||||
void desktop_free(Desktop* desktop);
|
void desktop_free(Desktop* desktop);
|
||||||
|
void desktop_lock(Desktop* desktop);
|
||||||
|
void desktop_unlock(Desktop* desktop);
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <toolbox/saved_struct.h>
|
#include <toolbox/saved_struct.h>
|
||||||
|
|
||||||
#define DESKTOP_SETTINGS_VER (1)
|
#define DESKTOP_SETTINGS_VER (2)
|
||||||
#define DESKTOP_SETTINGS_PATH "/int/desktop.settings"
|
#define DESKTOP_SETTINGS_PATH "/int/desktop.settings"
|
||||||
#define DESKTOP_SETTINGS_MAGIC (0x17)
|
#define DESKTOP_SETTINGS_MAGIC (0x17)
|
||||||
#define PIN_MAX_LENGTH 12
|
#define PIN_MAX_LENGTH 12
|
||||||
@ -39,6 +39,7 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
uint16_t favorite;
|
uint16_t favorite;
|
||||||
PinCode pin_code;
|
PinCode pin_code;
|
||||||
|
uint32_t auto_lock_delay_ms;
|
||||||
} DesktopSettings;
|
} DesktopSettings;
|
||||||
|
|
||||||
static inline bool pins_are_equal(const PinCode* pin_code1, const PinCode* pin_code2) {
|
static inline bool pins_are_equal(const PinCode* pin_code1, const PinCode* pin_code2) {
|
||||||
|
@ -36,12 +36,17 @@ DesktopSettingsApp* desktop_settings_app_alloc() {
|
|||||||
|
|
||||||
app->popup = popup_alloc();
|
app->popup = popup_alloc();
|
||||||
app->submenu = submenu_alloc();
|
app->submenu = submenu_alloc();
|
||||||
|
app->variable_item_list = variable_item_list_alloc();
|
||||||
app->pin_input_view = desktop_view_pin_input_alloc();
|
app->pin_input_view = desktop_view_pin_input_alloc();
|
||||||
app->pin_setup_howto_view = desktop_settings_view_pin_setup_howto_alloc();
|
app->pin_setup_howto_view = desktop_settings_view_pin_setup_howto_alloc();
|
||||||
app->pin_setup_howto2_view = desktop_settings_view_pin_setup_howto2_alloc();
|
app->pin_setup_howto2_view = desktop_settings_view_pin_setup_howto2_alloc();
|
||||||
|
|
||||||
view_dispatcher_add_view(
|
view_dispatcher_add_view(
|
||||||
app->view_dispatcher, DesktopSettingsAppViewMenu, submenu_get_view(app->submenu));
|
app->view_dispatcher, DesktopSettingsAppViewMenu, submenu_get_view(app->submenu));
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
app->view_dispatcher,
|
||||||
|
DesktopSettingsAppViewVarItemList,
|
||||||
|
variable_item_list_get_view(app->variable_item_list));
|
||||||
view_dispatcher_add_view(
|
view_dispatcher_add_view(
|
||||||
app->view_dispatcher, DesktopSettingsAppViewIdPopup, popup_get_view(app->popup));
|
app->view_dispatcher, DesktopSettingsAppViewIdPopup, popup_get_view(app->popup));
|
||||||
view_dispatcher_add_view(
|
view_dispatcher_add_view(
|
||||||
@ -63,10 +68,12 @@ void desktop_settings_app_free(DesktopSettingsApp* app) {
|
|||||||
furi_assert(app);
|
furi_assert(app);
|
||||||
// Variable item list
|
// Variable item list
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewMenu);
|
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewMenu);
|
||||||
|
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewVarItemList);
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPopup);
|
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPopup);
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinInput);
|
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinInput);
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto);
|
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto);
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto2);
|
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto2);
|
||||||
|
variable_item_list_free(app->variable_item_list);
|
||||||
submenu_free(app->submenu);
|
submenu_free(app->submenu);
|
||||||
popup_free(app->popup);
|
popup_free(app->popup);
|
||||||
desktop_view_pin_input_free(app->pin_input_view);
|
desktop_view_pin_input_free(app->pin_input_view);
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <gui/view_dispatcher.h>
|
#include <gui/view_dispatcher.h>
|
||||||
#include <gui/scene_manager.h>
|
#include <gui/scene_manager.h>
|
||||||
#include <gui/modules/submenu.h>
|
#include <gui/modules/submenu.h>
|
||||||
|
#include <gui/modules/variable_item_list.h>
|
||||||
|
|
||||||
#include "desktop_settings.h"
|
#include "desktop_settings.h"
|
||||||
#include "desktop/views/desktop_view_pin_input.h"
|
#include "desktop/views/desktop_view_pin_input.h"
|
||||||
@ -13,6 +14,7 @@
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DesktopSettingsAppViewMenu,
|
DesktopSettingsAppViewMenu,
|
||||||
|
DesktopSettingsAppViewVarItemList,
|
||||||
DesktopSettingsAppViewIdPopup,
|
DesktopSettingsAppViewIdPopup,
|
||||||
DesktopSettingsAppViewIdPinInput,
|
DesktopSettingsAppViewIdPinInput,
|
||||||
DesktopSettingsAppViewIdPinSetupHowto,
|
DesktopSettingsAppViewIdPinSetupHowto,
|
||||||
@ -25,6 +27,7 @@ typedef struct {
|
|||||||
Gui* gui;
|
Gui* gui;
|
||||||
SceneManager* scene_manager;
|
SceneManager* scene_manager;
|
||||||
ViewDispatcher* view_dispatcher;
|
ViewDispatcher* view_dispatcher;
|
||||||
|
VariableItemList* variable_item_list;
|
||||||
Submenu* submenu;
|
Submenu* submenu;
|
||||||
Popup* popup;
|
Popup* popup;
|
||||||
DesktopViewPinInput* pin_input_view;
|
DesktopViewPinInput* pin_input_view;
|
||||||
|
@ -1,35 +1,65 @@
|
|||||||
#include <applications.h>
|
#include <applications.h>
|
||||||
|
#include <lib/toolbox/value_index.h>
|
||||||
|
|
||||||
#include "../desktop_settings_app.h"
|
#include "../desktop_settings_app.h"
|
||||||
#include "desktop_settings_scene.h"
|
#include "desktop_settings_scene.h"
|
||||||
|
|
||||||
#define SCENE_EVENT_SELECT_FAVORITE 0
|
#define SCENE_EVENT_SELECT_FAVORITE 0
|
||||||
#define SCENE_EVENT_SELECT_PIN_SETUP 1
|
#define SCENE_EVENT_SELECT_PIN_SETUP 1
|
||||||
|
#define SCENE_EVENT_SELECT_AUTO_LOCK_DELAY 2
|
||||||
|
|
||||||
static void desktop_settings_scene_start_submenu_callback(void* context, uint32_t index) {
|
#define AUTO_LOCK_DELAY_COUNT 6
|
||||||
|
const char* const auto_lock_delay_text[AUTO_LOCK_DELAY_COUNT] = {
|
||||||
|
"OFF",
|
||||||
|
"30s",
|
||||||
|
"60s",
|
||||||
|
"2min",
|
||||||
|
"5min",
|
||||||
|
"10min",
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint32_t auto_lock_delay_value[AUTO_LOCK_DELAY_COUNT] =
|
||||||
|
{0, 30000, 60000, 120000, 300000, 600000};
|
||||||
|
|
||||||
|
static void desktop_settings_scene_start_var_list_enter_callback(void* context, uint32_t index) {
|
||||||
DesktopSettingsApp* app = context;
|
DesktopSettingsApp* app = context;
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void desktop_settings_scene_start_auto_lock_delay_changed(VariableItem* item) {
|
||||||
|
DesktopSettingsApp* app = variable_item_get_context(item);
|
||||||
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
|
|
||||||
|
variable_item_set_current_value_text(item, auto_lock_delay_text[index]);
|
||||||
|
app->settings.auto_lock_delay_ms = auto_lock_delay_value[index];
|
||||||
|
}
|
||||||
|
|
||||||
void desktop_settings_scene_start_on_enter(void* context) {
|
void desktop_settings_scene_start_on_enter(void* context) {
|
||||||
DesktopSettingsApp* app = context;
|
DesktopSettingsApp* app = context;
|
||||||
Submenu* submenu = app->submenu;
|
VariableItemList* variable_item_list = app->variable_item_list;
|
||||||
|
|
||||||
submenu_add_item(
|
VariableItem* item;
|
||||||
submenu,
|
uint8_t value_index;
|
||||||
"Favorite App",
|
|
||||||
SCENE_EVENT_SELECT_FAVORITE,
|
variable_item_list_add(variable_item_list, "Favorite App", 1, NULL, NULL);
|
||||||
desktop_settings_scene_start_submenu_callback,
|
|
||||||
|
variable_item_list_add(variable_item_list, "PIN Setup", 1, NULL, NULL);
|
||||||
|
|
||||||
|
item = variable_item_list_add(
|
||||||
|
variable_item_list,
|
||||||
|
"Auto Lock Time",
|
||||||
|
AUTO_LOCK_DELAY_COUNT,
|
||||||
|
desktop_settings_scene_start_auto_lock_delay_changed,
|
||||||
app);
|
app);
|
||||||
|
|
||||||
submenu_add_item(
|
variable_item_list_set_enter_callback(
|
||||||
submenu,
|
variable_item_list, desktop_settings_scene_start_var_list_enter_callback, app);
|
||||||
"PIN Setup",
|
value_index = value_index_uint32(
|
||||||
SCENE_EVENT_SELECT_PIN_SETUP,
|
app->settings.auto_lock_delay_ms, auto_lock_delay_value, AUTO_LOCK_DELAY_COUNT);
|
||||||
desktop_settings_scene_start_submenu_callback,
|
variable_item_set_current_value_index(item, value_index);
|
||||||
app);
|
variable_item_set_current_value_text(item, auto_lock_delay_text[value_index]);
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewMenu);
|
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewVarItemList);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent event) {
|
bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||||
@ -46,6 +76,9 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even
|
|||||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinMenu);
|
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinMenu);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
|
case SCENE_EVENT_SELECT_AUTO_LOCK_DELAY:
|
||||||
|
consumed = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return consumed;
|
return consumed;
|
||||||
@ -53,5 +86,6 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even
|
|||||||
|
|
||||||
void desktop_settings_scene_start_on_exit(void* context) {
|
void desktop_settings_scene_start_on_exit(void* context) {
|
||||||
DesktopSettingsApp* app = context;
|
DesktopSettingsApp* app = context;
|
||||||
submenu_reset(app->submenu);
|
variable_item_list_reset(app->variable_item_list);
|
||||||
|
SAVE_DESKTOP_SETTINGS(&app->settings);
|
||||||
}
|
}
|
||||||
|
@ -48,17 +48,13 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) {
|
|||||||
switch(event.event) {
|
switch(event.event) {
|
||||||
case DesktopLockMenuEventLock:
|
case DesktopLockMenuEventLock:
|
||||||
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0);
|
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0);
|
||||||
scene_manager_set_scene_state(
|
desktop_lock(desktop);
|
||||||
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER);
|
|
||||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked);
|
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
case DesktopLockMenuEventPinLock:
|
case DesktopLockMenuEventPinLock:
|
||||||
if(desktop->settings.pin_code.length > 0) {
|
if(desktop->settings.pin_code.length > 0) {
|
||||||
furi_hal_rtc_set_flag(FuriHalRtcFlagLock);
|
furi_hal_rtc_set_flag(FuriHalRtcFlagLock);
|
||||||
scene_manager_set_scene_state(
|
desktop_lock(desktop);
|
||||||
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER);
|
|
||||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked);
|
|
||||||
} else {
|
} else {
|
||||||
LoaderStatus status =
|
LoaderStatus status =
|
||||||
loader_start(desktop->loader, "Desktop", DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG);
|
loader_start(desktop->loader, "Desktop", DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG);
|
||||||
|
@ -81,13 +81,13 @@ bool desktop_scene_locked_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
switch(event.event) {
|
switch(event.event) {
|
||||||
case DesktopLockedEventUnlocked:
|
case DesktopLockedEventUnlocked:
|
||||||
furi_hal_rtc_set_pin_fails(0);
|
desktop_unlock(desktop);
|
||||||
desktop_helpers_unlock_system(desktop);
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
desktop->scene_manager, DesktopSceneMain);
|
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
case DesktopLockedEventUpdate:
|
case DesktopLockedEventUpdate:
|
||||||
|
if(desktop_view_locked_is_locked_hint_visible(desktop->locked_view)) {
|
||||||
|
notification_message(desktop->notification, &sequence_display_off);
|
||||||
|
}
|
||||||
desktop_view_locked_update(desktop->locked_view);
|
desktop_view_locked_update(desktop->locked_view);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
|
@ -129,16 +129,13 @@ bool desktop_scene_pin_input_on_event(void* context, SceneManagerEvent event) {
|
|||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
case DesktopPinInputEventUnlocked:
|
case DesktopPinInputEventUnlocked:
|
||||||
desktop_view_locked_unlock(desktop->locked_view);
|
desktop_unlock(desktop);
|
||||||
furi_hal_rtc_set_pin_fails(0);
|
|
||||||
desktop_helpers_unlock_system(desktop);
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
desktop->scene_manager, DesktopSceneMain);
|
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
case DesktopPinInputEventBack:
|
case DesktopPinInputEventBack:
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
scene_manager_search_and_switch_to_previous_scene(
|
||||||
desktop->scene_manager, DesktopSceneLocked);
|
desktop->scene_manager, DesktopSceneLocked);
|
||||||
|
notification_message(desktop->notification, &sequence_display_off);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -38,4 +38,5 @@ typedef enum {
|
|||||||
// Global events
|
// Global events
|
||||||
DesktopGlobalBeforeAppStarted,
|
DesktopGlobalBeforeAppStarted,
|
||||||
DesktopGlobalAfterAppFinished,
|
DesktopGlobalAfterAppFinished,
|
||||||
|
DesktopGlobalAutoLock,
|
||||||
} DesktopEvent;
|
} DesktopEvent;
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "desktop_view_locked.h"
|
#include "desktop_view_locked.h"
|
||||||
|
|
||||||
#define DOOR_MOVING_INTERVAL_MS (1000 / 16)
|
#define DOOR_MOVING_INTERVAL_MS (1000 / 16)
|
||||||
|
#define LOCKED_HINT_TIMEOUT_MS (1000)
|
||||||
#define UNLOCKED_HINT_TIMEOUT_MS (2000)
|
#define UNLOCKED_HINT_TIMEOUT_MS (2000)
|
||||||
|
|
||||||
#define DOOR_OFFSET_START -55
|
#define DOOR_OFFSET_START -55
|
||||||
@ -32,14 +33,18 @@ struct DesktopViewLocked {
|
|||||||
uint32_t lock_lastpress;
|
uint32_t lock_lastpress;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef enum {
|
||||||
uint32_t hint_icon_expire_at;
|
DesktopViewLockedStateUnlocked,
|
||||||
bool unlocked_hint;
|
DesktopViewLockedStateLocked,
|
||||||
bool locked;
|
DesktopViewLockedStateDoorsClosing,
|
||||||
bool pin_locked;
|
DesktopViewLockedStateLockedHintShown,
|
||||||
|
DesktopViewLockedStateUnlockedHintShown
|
||||||
|
} DesktopViewLockedState;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool pin_locked;
|
||||||
int8_t door_offset;
|
int8_t door_offset;
|
||||||
bool doors_closing;
|
DesktopViewLockedState view_state;
|
||||||
} DesktopViewLockedModel;
|
} DesktopViewLockedModel;
|
||||||
|
|
||||||
void desktop_view_locked_set_callback(
|
void desktop_view_locked_set_callback(
|
||||||
@ -78,51 +83,54 @@ static bool desktop_view_locked_doors_move(DesktopViewLockedModel* model) {
|
|||||||
|
|
||||||
static void desktop_view_locked_update_hint_icon_timeout(DesktopViewLocked* locked_view) {
|
static void desktop_view_locked_update_hint_icon_timeout(DesktopViewLocked* locked_view) {
|
||||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||||
model->hint_icon_expire_at = osKernelGetTickCount() + osKernelGetTickFreq();
|
const bool change_state = (model->view_state == DesktopViewLockedStateLocked) &&
|
||||||
view_commit_model(locked_view->view, true);
|
!model->pin_locked;
|
||||||
|
if(change_state) {
|
||||||
|
model->view_state = DesktopViewLockedStateLockedHintShown;
|
||||||
|
}
|
||||||
|
view_commit_model(locked_view->view, change_state);
|
||||||
|
xTimerChangePeriod(locked_view->timer, pdMS_TO_TICKS(LOCKED_HINT_TIMEOUT_MS), portMAX_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void desktop_view_locked_update(DesktopViewLocked* locked_view) {
|
void desktop_view_locked_update(DesktopViewLocked* locked_view) {
|
||||||
bool stop_timer = false;
|
|
||||||
|
|
||||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||||
if(model->locked) {
|
DesktopViewLockedState view_state = model->view_state;
|
||||||
model->doors_closing = desktop_view_locked_doors_move(model);
|
|
||||||
stop_timer = !model->doors_closing;
|
if(view_state == DesktopViewLockedStateDoorsClosing &&
|
||||||
} else {
|
!desktop_view_locked_doors_move(model)) {
|
||||||
model->unlocked_hint = false;
|
model->view_state = DesktopViewLockedStateLocked;
|
||||||
stop_timer = true;
|
} else if(view_state == DesktopViewLockedStateLockedHintShown) {
|
||||||
|
model->view_state = DesktopViewLockedStateLocked;
|
||||||
|
} else if(view_state == DesktopViewLockedStateUnlockedHintShown) {
|
||||||
|
model->view_state = DesktopViewLockedStateUnlocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
view_commit_model(locked_view->view, true);
|
view_commit_model(locked_view->view, true);
|
||||||
|
|
||||||
if(stop_timer) {
|
if(view_state != DesktopViewLockedStateDoorsClosing) {
|
||||||
xTimerStop(locked_view->timer, portMAX_DELAY);
|
xTimerStop(locked_view->timer, portMAX_DELAY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void desktop_view_locked_draw(Canvas* canvas, void* model) {
|
static void desktop_view_locked_draw(Canvas* canvas, void* model) {
|
||||||
DesktopViewLockedModel* m = model;
|
DesktopViewLockedModel* m = model;
|
||||||
uint32_t now = osKernelGetTickCount();
|
DesktopViewLockedState view_state = m->view_state;
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
if(m->locked) {
|
if(view_state == DesktopViewLockedStateDoorsClosing) {
|
||||||
if(m->doors_closing) {
|
desktop_view_locked_doors_draw(canvas, m);
|
||||||
desktop_view_locked_doors_draw(canvas, m);
|
canvas_set_font(canvas, FontPrimary);
|
||||||
canvas_set_font(canvas, FontPrimary);
|
elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Locked");
|
||||||
elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Locked");
|
} else if(view_state == DesktopViewLockedStateLockedHintShown) {
|
||||||
} else if((now < m->hint_icon_expire_at) && !m->pin_locked) {
|
canvas_set_font(canvas, FontSecondary);
|
||||||
canvas_set_font(canvas, FontSecondary);
|
elements_bold_rounded_frame(canvas, 14, 2 + STATUS_BAR_Y_SHIFT, 99, 48);
|
||||||
elements_bold_rounded_frame(canvas, 14, 2 + STATUS_BAR_Y_SHIFT, 99, 48);
|
elements_multiline_text(canvas, 65, 20 + STATUS_BAR_Y_SHIFT, "To unlock\npress:");
|
||||||
elements_multiline_text(canvas, 65, 20 + STATUS_BAR_Y_SHIFT, "To unlock\npress:");
|
canvas_draw_icon(canvas, 65, 36 + STATUS_BAR_Y_SHIFT, &I_Back3_45x8);
|
||||||
canvas_draw_icon(canvas, 65, 36 + STATUS_BAR_Y_SHIFT, &I_Back3_45x8);
|
canvas_draw_icon(canvas, 16, 7 + STATUS_BAR_Y_SHIFT, &I_WarningDolphin_45x42);
|
||||||
canvas_draw_icon(canvas, 16, 7 + STATUS_BAR_Y_SHIFT, &I_WarningDolphin_45x42);
|
canvas_draw_dot(canvas, 17, 61);
|
||||||
canvas_draw_dot(canvas, 17, 61);
|
} else if(view_state == DesktopViewLockedStateUnlockedHintShown) {
|
||||||
}
|
canvas_set_font(canvas, FontPrimary);
|
||||||
} else {
|
elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Unlocked");
|
||||||
if(m->unlocked_hint) {
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Unlocked");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,43 +142,38 @@ View* desktop_view_locked_get_view(DesktopViewLocked* locked_view) {
|
|||||||
static bool desktop_view_locked_input(InputEvent* event, void* context) {
|
static bool desktop_view_locked_input(InputEvent* event, void* context) {
|
||||||
furi_assert(event);
|
furi_assert(event);
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
|
|
||||||
|
bool is_changed = false;
|
||||||
|
const uint32_t press_time = xTaskGetTickCount();
|
||||||
DesktopViewLocked* locked_view = context;
|
DesktopViewLocked* locked_view = context;
|
||||||
bool locked = false;
|
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||||
bool locked_with_pin = false;
|
if(model->view_state == DesktopViewLockedStateUnlockedHintShown &&
|
||||||
bool doors_closing = false;
|
event->type == InputTypePress) {
|
||||||
uint32_t press_time = xTaskGetTickCount();
|
model->view_state = DesktopViewLockedStateUnlocked;
|
||||||
|
is_changed = true;
|
||||||
{
|
|
||||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
|
||||||
bool changed = false;
|
|
||||||
locked = model->locked;
|
|
||||||
locked_with_pin = model->pin_locked;
|
|
||||||
doors_closing = model->doors_closing;
|
|
||||||
if(!locked && model->unlocked_hint && event->type == InputTypePress) {
|
|
||||||
model->unlocked_hint = false;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
view_commit_model(locked_view->view, changed);
|
|
||||||
}
|
}
|
||||||
|
const DesktopViewLockedState view_state = model->view_state;
|
||||||
|
const bool pin_locked = model->pin_locked;
|
||||||
|
view_commit_model(locked_view->view, is_changed);
|
||||||
|
|
||||||
if(!locked || doors_closing || (event->type != InputTypeShort)) {
|
if(view_state == DesktopViewLockedStateUnlocked || event->type != InputTypeShort) {
|
||||||
return locked;
|
return view_state != DesktopViewLockedStateUnlocked;
|
||||||
}
|
} else if(view_state == DesktopViewLockedStateLocked && pin_locked) {
|
||||||
|
|
||||||
if(locked_with_pin) {
|
|
||||||
locked_view->callback(DesktopLockedEventShowPinInput, locked_view->context);
|
locked_view->callback(DesktopLockedEventShowPinInput, locked_view->context);
|
||||||
} else {
|
} else if(
|
||||||
|
view_state == DesktopViewLockedStateLocked ||
|
||||||
|
view_state == DesktopViewLockedStateLockedHintShown) {
|
||||||
if(press_time - locked_view->lock_lastpress > UNLOCK_RST_TIMEOUT) {
|
if(press_time - locked_view->lock_lastpress > UNLOCK_RST_TIMEOUT) {
|
||||||
locked_view->lock_lastpress = press_time;
|
locked_view->lock_lastpress = press_time;
|
||||||
locked_view->lock_count = 0;
|
locked_view->lock_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
desktop_view_locked_update_hint_icon_timeout(locked_view);
|
desktop_view_locked_update_hint_icon_timeout(locked_view);
|
||||||
|
|
||||||
if(event->key == InputKeyBack) {
|
if(event->key == InputKeyBack) {
|
||||||
locked_view->lock_lastpress = press_time;
|
locked_view->lock_lastpress = press_time;
|
||||||
locked_view->lock_count++;
|
locked_view->lock_count++;
|
||||||
if(locked_view->lock_count == UNLOCK_CNT) {
|
if(locked_view->lock_count == UNLOCK_CNT) {
|
||||||
desktop_view_locked_unlock(locked_view);
|
|
||||||
locked_view->callback(DesktopLockedEventUnlocked, locked_view->context);
|
locked_view->callback(DesktopLockedEventUnlocked, locked_view->context);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -180,7 +183,7 @@ static bool desktop_view_locked_input(InputEvent* event, void* context) {
|
|||||||
locked_view->lock_lastpress = press_time;
|
locked_view->lock_lastpress = press_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
return locked;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopViewLocked* desktop_view_locked_alloc() {
|
DesktopViewLocked* desktop_view_locked_alloc() {
|
||||||
@ -189,7 +192,6 @@ DesktopViewLocked* desktop_view_locked_alloc() {
|
|||||||
locked_view->timer =
|
locked_view->timer =
|
||||||
xTimerCreate(NULL, 1000 / 16, pdTRUE, locked_view, locked_view_timer_callback);
|
xTimerCreate(NULL, 1000 / 16, pdTRUE, locked_view, locked_view_timer_callback);
|
||||||
|
|
||||||
locked_view->view = view_alloc();
|
|
||||||
view_allocate_model(locked_view->view, ViewModelTypeLocking, sizeof(DesktopViewLockedModel));
|
view_allocate_model(locked_view->view, ViewModelTypeLocking, sizeof(DesktopViewLockedModel));
|
||||||
view_set_context(locked_view->view, locked_view);
|
view_set_context(locked_view->view, locked_view);
|
||||||
view_set_draw_callback(locked_view->view, desktop_view_locked_draw);
|
view_set_draw_callback(locked_view->view, desktop_view_locked_draw);
|
||||||
@ -207,7 +209,8 @@ void desktop_view_locked_free(DesktopViewLocked* locked_view) {
|
|||||||
|
|
||||||
void desktop_view_locked_close_doors(DesktopViewLocked* locked_view) {
|
void desktop_view_locked_close_doors(DesktopViewLocked* locked_view) {
|
||||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||||
model->doors_closing = true;
|
furi_assert(model->view_state == DesktopViewLockedStateLocked);
|
||||||
|
model->view_state = DesktopViewLockedStateDoorsClosing;
|
||||||
model->door_offset = DOOR_OFFSET_START;
|
model->door_offset = DOOR_OFFSET_START;
|
||||||
view_commit_model(locked_view->view, true);
|
view_commit_model(locked_view->view, true);
|
||||||
xTimerChangePeriod(locked_view->timer, pdMS_TO_TICKS(DOOR_MOVING_INTERVAL_MS), portMAX_DELAY);
|
xTimerChangePeriod(locked_view->timer, pdMS_TO_TICKS(DOOR_MOVING_INTERVAL_MS), portMAX_DELAY);
|
||||||
@ -215,19 +218,24 @@ void desktop_view_locked_close_doors(DesktopViewLocked* locked_view) {
|
|||||||
|
|
||||||
void desktop_view_locked_lock(DesktopViewLocked* locked_view, bool pin_locked) {
|
void desktop_view_locked_lock(DesktopViewLocked* locked_view, bool pin_locked) {
|
||||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||||
model->locked = true;
|
furi_assert(model->view_state == DesktopViewLockedStateUnlocked);
|
||||||
|
model->view_state = DesktopViewLockedStateLocked;
|
||||||
model->pin_locked = pin_locked;
|
model->pin_locked = pin_locked;
|
||||||
view_commit_model(locked_view->view, true);
|
view_commit_model(locked_view->view, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void desktop_view_locked_unlock(DesktopViewLocked* locked_view) {
|
void desktop_view_locked_unlock(DesktopViewLocked* locked_view) {
|
||||||
furi_assert(locked_view);
|
|
||||||
|
|
||||||
locked_view->lock_count = 0;
|
locked_view->lock_count = 0;
|
||||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||||
model->locked = false;
|
model->view_state = DesktopViewLockedStateUnlockedHintShown;
|
||||||
model->pin_locked = false;
|
model->pin_locked = false;
|
||||||
model->unlocked_hint = true;
|
|
||||||
view_commit_model(locked_view->view, true);
|
view_commit_model(locked_view->view, true);
|
||||||
xTimerChangePeriod(locked_view->timer, pdMS_TO_TICKS(UNLOCKED_HINT_TIMEOUT_MS), portMAX_DELAY);
|
xTimerChangePeriod(locked_view->timer, pdMS_TO_TICKS(UNLOCKED_HINT_TIMEOUT_MS), portMAX_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool desktop_view_locked_is_locked_hint_visible(DesktopViewLocked* locked_view) {
|
||||||
|
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||||
|
const DesktopViewLockedState view_state = model->view_state;
|
||||||
|
view_commit_model(locked_view->view, false);
|
||||||
|
return view_state == DesktopViewLockedStateLockedHintShown;
|
||||||
|
}
|
||||||
|
@ -19,3 +19,4 @@ void desktop_view_locked_free(DesktopViewLocked* locked_view);
|
|||||||
void desktop_view_locked_lock(DesktopViewLocked* locked_view, bool pin_locked);
|
void desktop_view_locked_lock(DesktopViewLocked* locked_view, bool pin_locked);
|
||||||
void desktop_view_locked_unlock(DesktopViewLocked* locked_view);
|
void desktop_view_locked_unlock(DesktopViewLocked* locked_view);
|
||||||
void desktop_view_locked_close_doors(DesktopViewLocked* locked_view);
|
void desktop_view_locked_close_doors(DesktopViewLocked* locked_view);
|
||||||
|
bool desktop_view_locked_is_locked_hint_visible(DesktopViewLocked* locked_view);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <furi_hal.h>
|
#include <furi_hal.h>
|
||||||
#include <storage/storage.h>
|
#include <storage/storage.h>
|
||||||
|
#include <input/input.h>
|
||||||
#include "notification.h"
|
#include "notification.h"
|
||||||
#include "notification_messages.h"
|
#include "notification_messages.h"
|
||||||
#include "notification_app.h"
|
#include "notification_app.h"
|
||||||
@ -416,8 +417,13 @@ static bool notification_save_settings(NotificationApp* app) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void input_event_callback(const void* value, void* context) {
|
static void input_event_callback(const void* value, void* context) {
|
||||||
|
furi_assert(value);
|
||||||
|
furi_assert(context);
|
||||||
|
const InputEvent* event = value;
|
||||||
NotificationApp* app = context;
|
NotificationApp* app = context;
|
||||||
notification_message(app, &sequence_display_on);
|
if(event->type == InputTypePress) {
|
||||||
|
notification_message(app, &sequence_display_on);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// App alloc
|
// App alloc
|
||||||
|
@ -21,7 +21,7 @@ const NotificationMessage message_display_lock = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const NotificationMessage message_display_unlock = {
|
const NotificationMessage message_display_unlock = {
|
||||||
.type = NotificationMessageTypeLedDisplayLock,
|
.type = NotificationMessageTypeLedDisplayUnlock,
|
||||||
.data.led.value = 0x00,
|
.data.led.value = 0x00,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -208,6 +208,12 @@ const NotificationSequence sequence_display_unlock = {
|
|||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const NotificationSequence sequence_display_off_delay_1000 = {
|
||||||
|
&message_delay_1000,
|
||||||
|
&message_display_off,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
// Charging
|
// Charging
|
||||||
const NotificationSequence sequence_charging = {
|
const NotificationSequence sequence_charging = {
|
||||||
&message_red_255,
|
&message_red_255,
|
||||||
@ -436,4 +442,4 @@ const NotificationSequence sequence_audiovisual_alert = {
|
|||||||
&message_sound_off,
|
&message_sound_off,
|
||||||
&message_vibro_off,
|
&message_vibro_off,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
@ -78,6 +78,8 @@ extern const NotificationSequence sequence_display_off;
|
|||||||
extern const NotificationSequence sequence_display_lock;
|
extern const NotificationSequence sequence_display_lock;
|
||||||
/** Display: backlight always on unlock */
|
/** Display: backlight always on unlock */
|
||||||
extern const NotificationSequence sequence_display_unlock;
|
extern const NotificationSequence sequence_display_unlock;
|
||||||
|
/** Display: backlight force off after a delay of 1000ms */
|
||||||
|
extern const NotificationSequence sequence_display_off_delay_1000;
|
||||||
|
|
||||||
// Charging
|
// Charging
|
||||||
extern const NotificationSequence sequence_charging;
|
extern const NotificationSequence sequence_charging;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "notification_app.h"
|
#include "notification_app.h"
|
||||||
#include <gui/modules/variable_item_list.h>
|
#include <gui/modules/variable_item_list.h>
|
||||||
#include <gui/view_dispatcher.h>
|
#include <gui/view_dispatcher.h>
|
||||||
|
#include <lib/toolbox/value_index.h>
|
||||||
|
|
||||||
#define MAX_NOTIFICATION_SETTINGS 4
|
#define MAX_NOTIFICATION_SETTINGS 4
|
||||||
|
|
||||||
@ -63,44 +64,6 @@ const char* const vibro_text[VIBRO_COUNT] = {
|
|||||||
};
|
};
|
||||||
const bool vibro_value[VIBRO_COUNT] = {false, true};
|
const bool vibro_value[VIBRO_COUNT] = {false, true};
|
||||||
|
|
||||||
uint8_t float_value_index(const float value, const float values[], uint8_t values_count) {
|
|
||||||
const float epsilon = 0.01f;
|
|
||||||
float last_value = values[0];
|
|
||||||
uint8_t index = 0;
|
|
||||||
for(uint8_t i = 0; i < values_count; i++) {
|
|
||||||
if((value >= last_value - epsilon) && (value <= values[i] + epsilon)) {
|
|
||||||
index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
last_value = values[i];
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t uint32_value_index(const uint32_t value, const uint32_t values[], uint8_t values_count) {
|
|
||||||
int64_t last_value = INT64_MIN;
|
|
||||||
uint8_t index = 0;
|
|
||||||
for(uint8_t i = 0; i < values_count; i++) {
|
|
||||||
if((value >= last_value) && (value <= values[i])) {
|
|
||||||
index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
last_value = values[i];
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t bool_value_index(const bool value, const bool values[], uint8_t values_count) {
|
|
||||||
uint8_t index = 0;
|
|
||||||
for(uint8_t i = 0; i < values_count; i++) {
|
|
||||||
if(value == values[i]) {
|
|
||||||
index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void backlight_changed(VariableItem* item) {
|
static void backlight_changed(VariableItem* item) {
|
||||||
NotificationAppSettings* app = variable_item_get_context(item);
|
NotificationAppSettings* app = variable_item_get_context(item);
|
||||||
uint8_t index = variable_item_get_current_value_index(item);
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
@ -164,21 +127,21 @@ static NotificationAppSettings* alloc_settings() {
|
|||||||
|
|
||||||
item = variable_item_list_add(
|
item = variable_item_list_add(
|
||||||
app->variable_item_list, "LCD Backlight", BACKLIGHT_COUNT, backlight_changed, app);
|
app->variable_item_list, "LCD Backlight", BACKLIGHT_COUNT, backlight_changed, app);
|
||||||
value_index = float_value_index(
|
value_index = value_index_float(
|
||||||
app->notification->settings.display_brightness, backlight_value, BACKLIGHT_COUNT);
|
app->notification->settings.display_brightness, backlight_value, BACKLIGHT_COUNT);
|
||||||
variable_item_set_current_value_index(item, value_index);
|
variable_item_set_current_value_index(item, value_index);
|
||||||
variable_item_set_current_value_text(item, backlight_text[value_index]);
|
variable_item_set_current_value_text(item, backlight_text[value_index]);
|
||||||
|
|
||||||
item = variable_item_list_add(
|
item = variable_item_list_add(
|
||||||
app->variable_item_list, "Backlight Time", DELAY_COUNT, screen_changed, app);
|
app->variable_item_list, "Backlight Time", DELAY_COUNT, screen_changed, app);
|
||||||
value_index = uint32_value_index(
|
value_index = value_index_uint32(
|
||||||
app->notification->settings.display_off_delay_ms, delay_value, DELAY_COUNT);
|
app->notification->settings.display_off_delay_ms, delay_value, DELAY_COUNT);
|
||||||
variable_item_set_current_value_index(item, value_index);
|
variable_item_set_current_value_index(item, value_index);
|
||||||
variable_item_set_current_value_text(item, delay_text[value_index]);
|
variable_item_set_current_value_text(item, delay_text[value_index]);
|
||||||
|
|
||||||
item = variable_item_list_add(
|
item = variable_item_list_add(
|
||||||
app->variable_item_list, "LED Brightness", BACKLIGHT_COUNT, led_changed, app);
|
app->variable_item_list, "LED Brightness", BACKLIGHT_COUNT, led_changed, app);
|
||||||
value_index = float_value_index(
|
value_index = value_index_float(
|
||||||
app->notification->settings.led_brightness, backlight_value, BACKLIGHT_COUNT);
|
app->notification->settings.led_brightness, backlight_value, BACKLIGHT_COUNT);
|
||||||
variable_item_set_current_value_index(item, value_index);
|
variable_item_set_current_value_index(item, value_index);
|
||||||
variable_item_set_current_value_text(item, backlight_text[value_index]);
|
variable_item_set_current_value_text(item, backlight_text[value_index]);
|
||||||
@ -186,13 +149,13 @@ static NotificationAppSettings* alloc_settings() {
|
|||||||
item = variable_item_list_add(
|
item = variable_item_list_add(
|
||||||
app->variable_item_list, "Volume", VOLUME_COUNT, volume_changed, app);
|
app->variable_item_list, "Volume", VOLUME_COUNT, volume_changed, app);
|
||||||
value_index =
|
value_index =
|
||||||
float_value_index(app->notification->settings.speaker_volume, volume_value, VOLUME_COUNT);
|
value_index_float(app->notification->settings.speaker_volume, volume_value, VOLUME_COUNT);
|
||||||
variable_item_set_current_value_index(item, value_index);
|
variable_item_set_current_value_index(item, value_index);
|
||||||
variable_item_set_current_value_text(item, volume_text[value_index]);
|
variable_item_set_current_value_text(item, volume_text[value_index]);
|
||||||
|
|
||||||
item =
|
item =
|
||||||
variable_item_list_add(app->variable_item_list, "Vibro", VIBRO_COUNT, vibro_changed, app);
|
variable_item_list_add(app->variable_item_list, "Vibro", VIBRO_COUNT, vibro_changed, app);
|
||||||
value_index = bool_value_index(app->notification->settings.vibro_on, vibro_value, VIBRO_COUNT);
|
value_index = value_index_bool(app->notification->settings.vibro_on, vibro_value, VIBRO_COUNT);
|
||||||
variable_item_set_current_value_index(item, value_index);
|
variable_item_set_current_value_index(item, value_index);
|
||||||
variable_item_set_current_value_text(item, vibro_text[value_index]);
|
variable_item_set_current_value_text(item, vibro_text[value_index]);
|
||||||
|
|
||||||
|
@ -1,19 +1,6 @@
|
|||||||
#include "system_settings.h"
|
#include "system_settings.h"
|
||||||
#include <loader/loader.h>
|
#include <loader/loader.h>
|
||||||
|
#include <lib/toolbox/value_index.h>
|
||||||
static uint8_t
|
|
||||||
uint32_value_index(const uint32_t value, const uint32_t values[], uint8_t values_count) {
|
|
||||||
int64_t last_value = INT64_MIN;
|
|
||||||
uint8_t index = 0;
|
|
||||||
for(uint8_t i = 0; i < values_count; i++) {
|
|
||||||
if((value >= last_value) && (value <= values[i])) {
|
|
||||||
index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
last_value = values[i];
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* const log_level_text[] = {
|
const char* const log_level_text[] = {
|
||||||
"Default",
|
"Default",
|
||||||
@ -80,7 +67,7 @@ SystemSettings* system_settings_alloc() {
|
|||||||
|
|
||||||
item = variable_item_list_add(
|
item = variable_item_list_add(
|
||||||
app->var_item_list, "Log Level", COUNT_OF(log_level_text), log_level_changed, app);
|
app->var_item_list, "Log Level", COUNT_OF(log_level_text), log_level_changed, app);
|
||||||
value_index = uint32_value_index(
|
value_index = value_index_uint32(
|
||||||
furi_hal_rtc_get_log_level(), log_level_value, COUNT_OF(log_level_text));
|
furi_hal_rtc_get_log_level(), log_level_value, COUNT_OF(log_level_text));
|
||||||
variable_item_set_current_value_index(item, value_index);
|
variable_item_set_current_value_index(item, value_index);
|
||||||
variable_item_set_current_value_text(item, log_level_text[value_index]);
|
variable_item_set_current_value_text(item, log_level_text[value_index]);
|
||||||
|
@ -26,6 +26,10 @@ uint32_t furi_hal_get_tick(void) {
|
|||||||
return tick_cnt;
|
return tick_cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t furi_hal_ms_to_ticks(float milliseconds) {
|
||||||
|
return milliseconds / (1000.0f / osKernelGetTickFreq());
|
||||||
|
}
|
||||||
|
|
||||||
void furi_hal_delay_us(float microseconds) {
|
void furi_hal_delay_us(float microseconds) {
|
||||||
uint32_t start = DWT->CYCCNT;
|
uint32_t start = DWT->CYCCNT;
|
||||||
uint32_t time_ticks = microseconds * furi_hal_delay_instructions_per_microsecond();
|
uint32_t time_ticks = microseconds * furi_hal_delay_instructions_per_microsecond();
|
||||||
|
@ -31,6 +31,13 @@ void furi_hal_tick(void);
|
|||||||
*/
|
*/
|
||||||
uint32_t furi_hal_get_tick(void);
|
uint32_t furi_hal_get_tick(void);
|
||||||
|
|
||||||
|
/** Convert milliseconds to ticks
|
||||||
|
*
|
||||||
|
* @param[in] milliseconds time in milliseconds
|
||||||
|
* @return time in ticks
|
||||||
|
*/
|
||||||
|
uint32_t furi_hal_ms_to_ticks(float milliseconds);
|
||||||
|
|
||||||
/** Delay in milliseconds
|
/** Delay in milliseconds
|
||||||
* @warning Cannot be used from ISR
|
* @warning Cannot be used from ISR
|
||||||
*
|
*
|
||||||
|
39
lib/toolbox/value_index.c
Normal file
39
lib/toolbox/value_index.c
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#include "value_index.h"
|
||||||
|
|
||||||
|
uint8_t value_index_uint32(const uint32_t value, const uint32_t values[], uint8_t values_count) {
|
||||||
|
int64_t last_value = INT64_MIN;
|
||||||
|
uint8_t index = 0;
|
||||||
|
for(uint8_t i = 0; i < values_count; i++) {
|
||||||
|
if((value >= last_value) && (value <= values[i])) {
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last_value = values[i];
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t value_index_float(const float value, const float values[], uint8_t values_count) {
|
||||||
|
const float epsilon = 0.01f;
|
||||||
|
float last_value = values[0];
|
||||||
|
uint8_t index = 0;
|
||||||
|
for(uint8_t i = 0; i < values_count; i++) {
|
||||||
|
if((value >= last_value - epsilon) && (value <= values[i] + epsilon)) {
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last_value = values[i];
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t value_index_bool(const bool value, const bool values[], uint8_t values_count) {
|
||||||
|
uint8_t index = 0;
|
||||||
|
for(uint8_t i = 0; i < values_count; i++) {
|
||||||
|
if(value == values[i]) {
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
51
lib/toolbox/value_index.h
Normal file
51
lib/toolbox/value_index.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Get the index of a uint32_t array element which is closest to the given value.
|
||||||
|
*
|
||||||
|
* Returned index corresponds to the first element found.
|
||||||
|
* If no suitable elements were found, the function returns 0.
|
||||||
|
*
|
||||||
|
* @param value value to be searched.
|
||||||
|
* @param values pointer to the array to perform the search in.
|
||||||
|
* @param values_count array size.
|
||||||
|
*
|
||||||
|
* @return value's index.
|
||||||
|
*/
|
||||||
|
uint8_t value_index_uint32(const uint32_t value, const uint32_t values[], uint8_t values_count);
|
||||||
|
|
||||||
|
/** Get the index of a float array element which is closest to the given value.
|
||||||
|
*
|
||||||
|
* Returned index corresponds to the first element found.
|
||||||
|
* If no suitable elements were found, the function returns 0.
|
||||||
|
*
|
||||||
|
* @param value value to be searched.
|
||||||
|
* @param values pointer to the array to perform the search in.
|
||||||
|
* @param values_count array size.
|
||||||
|
*
|
||||||
|
* @return value's index.
|
||||||
|
*/
|
||||||
|
uint8_t value_index_float(const float value, const float values[], uint8_t values_count);
|
||||||
|
|
||||||
|
/** Get the index of a bool array element which is equal to the given value.
|
||||||
|
*
|
||||||
|
* Returned index corresponds to the first element found.
|
||||||
|
* If no suitable elements were found, the function returns 0.
|
||||||
|
*
|
||||||
|
* @param value value to be searched.
|
||||||
|
* @param values pointer to the array to perform the search in.
|
||||||
|
* @param values_count array size.
|
||||||
|
*
|
||||||
|
* @return value's index.
|
||||||
|
*/
|
||||||
|
uint8_t value_index_bool(const bool value, const bool values[], uint8_t values_count);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user