#include #include #include #include #include #include "animations/animation_manager.h" #include "desktop/scenes/desktop_scene.h" #include "desktop/scenes/desktop_scene_i.h" #include "desktop/views/desktop_view_locked.h" #include "desktop/views/desktop_view_pin_input.h" #include "desktop/views/desktop_view_pin_timeout.h" #include "desktop_i.h" #include "desktop_helpers.h" static void desktop_loader_callback(const void* message, void* context) { furi_assert(context); Desktop* desktop = context; const LoaderEvent* event = message; if(event->type == LoaderEventTypeApplicationStarted) { view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalBeforeAppStarted); } else if(event->type == LoaderEventTypeApplicationStopped) { view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalAfterAppFinished); } } static void desktop_lock_icon_callback(Canvas* canvas, void* context) { furi_assert(canvas); canvas_draw_icon(canvas, 0, 0, &I_Lock_8x8); } static bool desktop_custom_event_callback(void* context, uint32_t event) { furi_assert(context); Desktop* desktop = (Desktop*)context; switch(event) { case DesktopGlobalBeforeAppStarted: animation_manager_unload_and_stall_animation(desktop->animation_manager); return true; case DesktopGlobalAfterAppFinished: animation_manager_load_and_continue_animation(desktop->animation_manager); return true; } return scene_manager_handle_custom_event(desktop->scene_manager, event); } static bool desktop_back_event_callback(void* context) { furi_assert(context); Desktop* desktop = (Desktop*)context; return scene_manager_handle_back_event(desktop->scene_manager); } static void desktop_tick_event_callback(void* context) { furi_assert(context); Desktop* app = context; scene_manager_handle_tick_event(app->scene_manager); } Desktop* desktop_alloc() { Desktop* desktop = malloc(sizeof(Desktop)); desktop->animation_manager = animation_manager_alloc(); desktop->gui = furi_record_open("gui"); desktop->scene_thread = furi_thread_alloc(); desktop->view_dispatcher = view_dispatcher_alloc(); desktop->scene_manager = scene_manager_alloc(&desktop_scene_handlers, desktop); view_dispatcher_enable_queue(desktop->view_dispatcher); view_dispatcher_attach_to_gui( desktop->view_dispatcher, desktop->gui, ViewDispatcherTypeDesktop); view_dispatcher_set_tick_event_callback( desktop->view_dispatcher, desktop_tick_event_callback, 500); view_dispatcher_set_event_callback_context(desktop->view_dispatcher, desktop); view_dispatcher_set_custom_event_callback( desktop->view_dispatcher, desktop_custom_event_callback); view_dispatcher_set_navigation_event_callback( desktop->view_dispatcher, desktop_back_event_callback); desktop->lock_menu = desktop_lock_menu_alloc(); desktop->debug_view = desktop_debug_alloc(); desktop->first_start_view = desktop_first_start_alloc(); desktop->hw_mismatch_popup = popup_alloc(); desktop->locked_view = desktop_view_locked_alloc(); desktop->pin_input_view = desktop_view_pin_input_alloc(); desktop->pin_timeout_view = desktop_view_pin_timeout_alloc(); desktop->main_view_stack = view_stack_alloc(); desktop->main_view = desktop_main_alloc(); View* dolphin_view = animation_manager_get_animation_view(desktop->animation_manager); view_stack_add_view(desktop->main_view_stack, desktop_main_get_view(desktop->main_view)); view_stack_add_view(desktop->main_view_stack, dolphin_view); view_stack_add_view( desktop->main_view_stack, desktop_view_locked_get_view(desktop->locked_view)); /* locked view (as animation view) attends in 2 scenes: main & locked, * because it has to draw "Unlocked" label on main scene */ desktop->locked_view_stack = view_stack_alloc(); view_stack_add_view(desktop->locked_view_stack, dolphin_view); view_stack_add_view( desktop->locked_view_stack, desktop_view_locked_get_view(desktop->locked_view)); view_dispatcher_add_view( desktop->view_dispatcher, DesktopViewIdMain, view_stack_get_view(desktop->main_view_stack)); view_dispatcher_add_view( desktop->view_dispatcher, DesktopViewIdLocked, view_stack_get_view(desktop->locked_view_stack)); view_dispatcher_add_view( desktop->view_dispatcher, DesktopViewIdLockMenu, desktop_lock_menu_get_view(desktop->lock_menu)); view_dispatcher_add_view( desktop->view_dispatcher, DesktopViewIdDebug, desktop_debug_get_view(desktop->debug_view)); view_dispatcher_add_view( desktop->view_dispatcher, DesktopViewIdFirstStart, desktop_first_start_get_view(desktop->first_start_view)); view_dispatcher_add_view( desktop->view_dispatcher, DesktopViewIdHwMismatch, popup_get_view(desktop->hw_mismatch_popup)); view_dispatcher_add_view( desktop->view_dispatcher, DesktopViewIdPinTimeout, desktop_view_pin_timeout_get_view(desktop->pin_timeout_view)); view_dispatcher_add_view( desktop->view_dispatcher, DesktopViewIdPinInput, desktop_view_pin_input_get_view(desktop->pin_input_view)); // Lock icon desktop->lock_viewport = view_port_alloc(); view_port_set_width(desktop->lock_viewport, icon_get_width(&I_Lock_8x8)); view_port_draw_callback_set(desktop->lock_viewport, desktop_lock_icon_callback, desktop); view_port_enabled_set(desktop->lock_viewport, false); gui_add_view_port(desktop->gui, desktop->lock_viewport, GuiLayerStatusBarLeft); // Special case: autostart application is already running desktop->loader = furi_record_open("loader"); if(loader_is_locked(desktop->loader) && animation_manager_is_animation_loaded(desktop->animation_manager)) { animation_manager_unload_and_stall_animation(desktop->animation_manager); } desktop->app_start_stop_subscription = furi_pubsub_subscribe( loader_get_pubsub(desktop->loader), desktop_loader_callback, desktop); return desktop; } void desktop_free(Desktop* desktop) { furi_assert(desktop); furi_pubsub_unsubscribe( loader_get_pubsub(desktop->loader), desktop->app_start_stop_subscription); desktop->loader = NULL; furi_record_close("loader"); view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdMain); view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLockMenu); view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLocked); view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdDebug); view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdFirstStart); view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdHwMismatch); view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdPinInput); view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdPinTimeout); view_dispatcher_free(desktop->view_dispatcher); scene_manager_free(desktop->scene_manager); animation_manager_free(desktop->animation_manager); view_stack_free(desktop->main_view_stack); desktop_main_free(desktop->main_view); view_stack_free(desktop->locked_view_stack); desktop_view_locked_free(desktop->locked_view); desktop_lock_menu_free(desktop->lock_menu); desktop_view_locked_free(desktop->locked_view); desktop_debug_free(desktop->debug_view); desktop_first_start_free(desktop->first_start_view); popup_free(desktop->hw_mismatch_popup); desktop_view_pin_timeout_free(desktop->pin_timeout_view); furi_record_close("gui"); desktop->gui = NULL; furi_thread_free(desktop->scene_thread); furi_record_close("menu"); free(desktop); } static bool desktop_is_first_start() { Storage* storage = furi_record_open("storage"); bool exists = storage_common_stat(storage, "/int/first_start", NULL) == FSE_OK; furi_record_close("storage"); return exists; } int32_t desktop_srv(void* p) { Desktop* desktop = desktop_alloc(); bool loaded = LOAD_DESKTOP_SETTINGS(&desktop->settings); if(!loaded) { furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); memset(&desktop->settings, 0, sizeof(desktop->settings)); SAVE_DESKTOP_SETTINGS(&desktop->settings); } scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) { if(desktop->settings.pin_code.length > 0) { scene_manager_set_scene_state( desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER); scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked); } else { furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); } } if(desktop_is_first_start()) { scene_manager_next_scene(desktop->scene_manager, DesktopSceneFirstStart); } if(!furi_hal_version_do_i_belong_here()) { scene_manager_next_scene(desktop->scene_manager, DesktopSceneHwMismatch); } if(furi_hal_rtc_get_fault_data()) { scene_manager_next_scene(desktop->scene_manager, DesktopSceneFault); } view_dispatcher_run(desktop->view_dispatcher); desktop_free(desktop); return 0; }