[FL-3171] Introduce stealth mode and auto-selective lock (#2576)
* Introduce stealth mode and auto-selective lock * Stealth mode status bar icon * Review fixes * Fix icon disappearing after reboot * Support overriding stealth mode * FuriHal: correct reserved space size in RTC SystemReg Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									2c7eb53cac
								
							
						
					
					
						commit
						74fe003f8b
					
				| @ -46,6 +46,12 @@ static void desktop_dummy_mode_icon_draw_callback(Canvas* canvas, void* context) | ||||
|     canvas_draw_icon(canvas, 0, 0, &I_GameMode_11x8); | ||||
| } | ||||
| 
 | ||||
| static void desktop_stealth_mode_icon_draw_callback(Canvas* canvas, void* context) { | ||||
|     UNUSED(context); | ||||
|     furi_assert(canvas); | ||||
|     canvas_draw_icon(canvas, 0, 0, &I_Muted_8x8); | ||||
| } | ||||
| 
 | ||||
| static bool desktop_custom_event_callback(void* context, uint32_t event) { | ||||
|     furi_assert(context); | ||||
|     Desktop* desktop = (Desktop*)context; | ||||
| @ -153,6 +159,17 @@ void desktop_set_dummy_mode_state(Desktop* desktop, bool enabled) { | ||||
|     desktop->in_transition = false; | ||||
| } | ||||
| 
 | ||||
| void desktop_set_stealth_mode_state(Desktop* desktop, bool enabled) { | ||||
|     desktop->in_transition = true; | ||||
|     if(enabled) { | ||||
|         furi_hal_rtc_set_flag(FuriHalRtcFlagStealthMode); | ||||
|     } else { | ||||
|         furi_hal_rtc_reset_flag(FuriHalRtcFlagStealthMode); | ||||
|     } | ||||
|     view_port_enabled_set(desktop->stealth_mode_icon_viewport, enabled); | ||||
|     desktop->in_transition = false; | ||||
| } | ||||
| 
 | ||||
| Desktop* desktop_alloc() { | ||||
|     Desktop* desktop = malloc(sizeof(Desktop)); | ||||
| 
 | ||||
| @ -244,6 +261,18 @@ Desktop* desktop_alloc() { | ||||
|     view_port_enabled_set(desktop->dummy_mode_icon_viewport, false); | ||||
|     gui_add_view_port(desktop->gui, desktop->dummy_mode_icon_viewport, GuiLayerStatusBarLeft); | ||||
| 
 | ||||
|     // Stealth mode icon
 | ||||
|     desktop->stealth_mode_icon_viewport = view_port_alloc(); | ||||
|     view_port_set_width(desktop->stealth_mode_icon_viewport, icon_get_width(&I_Muted_8x8)); | ||||
|     view_port_draw_callback_set( | ||||
|         desktop->stealth_mode_icon_viewport, desktop_stealth_mode_icon_draw_callback, desktop); | ||||
|     if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) { | ||||
|         view_port_enabled_set(desktop->stealth_mode_icon_viewport, true); | ||||
|     } else { | ||||
|         view_port_enabled_set(desktop->stealth_mode_icon_viewport, false); | ||||
|     } | ||||
|     gui_add_view_port(desktop->gui, desktop->stealth_mode_icon_viewport, GuiLayerStatusBarLeft); | ||||
| 
 | ||||
|     // Special case: autostart application is already running
 | ||||
|     desktop->loader = furi_record_open(RECORD_LOADER); | ||||
|     if(loader_is_locked(desktop->loader) && | ||||
|  | ||||
| @ -59,6 +59,7 @@ struct Desktop { | ||||
| 
 | ||||
|     ViewPort* lock_icon_viewport; | ||||
|     ViewPort* dummy_mode_icon_viewport; | ||||
|     ViewPort* stealth_mode_icon_viewport; | ||||
| 
 | ||||
|     AnimationManager* animation_manager; | ||||
| 
 | ||||
| @ -79,3 +80,4 @@ void desktop_free(Desktop* desktop); | ||||
| void desktop_lock(Desktop* desktop); | ||||
| void desktop_unlock(Desktop* desktop); | ||||
| void desktop_set_dummy_mode_state(Desktop* desktop, bool enabled); | ||||
| void desktop_set_stealth_mode_state(Desktop* desktop, bool enabled); | ||||
|  | ||||
| @ -27,6 +27,8 @@ void desktop_scene_lock_menu_on_enter(void* context) { | ||||
|     desktop_lock_menu_set_callback(desktop->lock_menu, desktop_scene_lock_menu_callback, desktop); | ||||
|     desktop_lock_menu_set_pin_state(desktop->lock_menu, desktop->settings.pin_code.length > 0); | ||||
|     desktop_lock_menu_set_dummy_mode_state(desktop->lock_menu, desktop->settings.dummy_mode); | ||||
|     desktop_lock_menu_set_stealth_mode_state( | ||||
|         desktop->lock_menu, furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)); | ||||
|     desktop_lock_menu_set_idx(desktop->lock_menu, 0); | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdLockMenu); | ||||
| @ -78,6 +80,16 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { | ||||
|             scene_manager_search_and_switch_to_previous_scene( | ||||
|                 desktop->scene_manager, DesktopSceneMain); | ||||
|             break; | ||||
|         case DesktopLockMenuEventStealthModeOn: | ||||
|             desktop_set_stealth_mode_state(desktop, true); | ||||
|             scene_manager_search_and_switch_to_previous_scene( | ||||
|                 desktop->scene_manager, DesktopSceneMain); | ||||
|             break; | ||||
|         case DesktopLockMenuEventStealthModeOff: | ||||
|             desktop_set_stealth_mode_state(desktop, false); | ||||
|             scene_manager_search_and_switch_to_previous_scene( | ||||
|                 desktop->scene_manager, DesktopSceneMain); | ||||
|             break; | ||||
|         default: | ||||
|             break; | ||||
|         } | ||||
|  | ||||
| @ -34,6 +34,8 @@ typedef enum { | ||||
|     DesktopLockMenuEventPinLock, | ||||
|     DesktopLockMenuEventDummyModeOn, | ||||
|     DesktopLockMenuEventDummyModeOff, | ||||
|     DesktopLockMenuEventStealthModeOn, | ||||
|     DesktopLockMenuEventStealthModeOff, | ||||
| 
 | ||||
|     DesktopAnimationEventCheckAnimation, | ||||
|     DesktopAnimationEventNewIdleAnimation, | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
| 
 | ||||
| typedef enum { | ||||
|     DesktopLockMenuIndexLock, | ||||
|     DesktopLockMenuIndexPinLock, | ||||
|     DesktopLockMenuIndexStealth, | ||||
|     DesktopLockMenuIndexDummy, | ||||
| 
 | ||||
|     DesktopLockMenuIndexTotalCount | ||||
| @ -39,6 +39,14 @@ void desktop_lock_menu_set_dummy_mode_state(DesktopLockMenuView* lock_menu, bool | ||||
|         true); | ||||
| } | ||||
| 
 | ||||
| void desktop_lock_menu_set_stealth_mode_state(DesktopLockMenuView* lock_menu, bool stealth_mode) { | ||||
|     with_view_model( | ||||
|         lock_menu->view, | ||||
|         DesktopLockMenuViewModel * model, | ||||
|         { model->stealth_mode = stealth_mode; }, | ||||
|         true); | ||||
| } | ||||
| 
 | ||||
| void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx) { | ||||
|     furi_assert(idx < DesktopLockMenuIndexTotalCount); | ||||
|     with_view_model( | ||||
| @ -58,11 +66,11 @@ void desktop_lock_menu_draw_callback(Canvas* canvas, void* model) { | ||||
| 
 | ||||
|         if(i == DesktopLockMenuIndexLock) { | ||||
|             str = "Lock"; | ||||
|         } else if(i == DesktopLockMenuIndexPinLock) { | ||||
|             if(m->pin_is_set) { | ||||
|                 str = "Lock with PIN"; | ||||
|         } else if(i == DesktopLockMenuIndexStealth) { | ||||
|             if(m->stealth_mode) { | ||||
|                 str = "Sound Mode"; | ||||
|             } else { | ||||
|                 str = "Set PIN"; | ||||
|                 str = "Stealth Mode"; | ||||
|             } | ||||
|         } else if(i == DesktopLockMenuIndexDummy) { //-V547
 | ||||
|             if(m->dummy_mode) { | ||||
| @ -93,6 +101,8 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) { | ||||
|     uint8_t idx = 0; | ||||
|     bool consumed = false; | ||||
|     bool dummy_mode = false; | ||||
|     bool stealth_mode = false; | ||||
|     bool pin_is_set = false; | ||||
|     bool update = false; | ||||
| 
 | ||||
|     with_view_model( | ||||
| @ -120,14 +130,24 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) { | ||||
|             } | ||||
|             idx = model->idx; | ||||
|             dummy_mode = model->dummy_mode; | ||||
|             stealth_mode = model->stealth_mode; | ||||
|             pin_is_set = model->pin_is_set; | ||||
|         }, | ||||
|         update); | ||||
| 
 | ||||
|     if(event->key == InputKeyOk) { | ||||
|         if((idx == DesktopLockMenuIndexLock) && (event->type == InputTypeShort)) { | ||||
|             lock_menu->callback(DesktopLockMenuEventLock, lock_menu->context); | ||||
|         } else if((idx == DesktopLockMenuIndexPinLock) && (event->type == InputTypeShort)) { | ||||
|             lock_menu->callback(DesktopLockMenuEventPinLock, lock_menu->context); | ||||
|         if((idx == DesktopLockMenuIndexLock)) { | ||||
|             if((pin_is_set) && (event->type == InputTypeShort)) { | ||||
|                 lock_menu->callback(DesktopLockMenuEventPinLock, lock_menu->context); | ||||
|             } else if((pin_is_set == false) && (event->type == InputTypeShort)) { | ||||
|                 lock_menu->callback(DesktopLockMenuEventLock, lock_menu->context); | ||||
|             } | ||||
|         } else if(idx == DesktopLockMenuIndexStealth) { | ||||
|             if((stealth_mode == false) && (event->type == InputTypeShort)) { | ||||
|                 lock_menu->callback(DesktopLockMenuEventStealthModeOn, lock_menu->context); | ||||
|             } else if((stealth_mode == true) && (event->type == InputTypeShort)) { | ||||
|                 lock_menu->callback(DesktopLockMenuEventStealthModeOff, lock_menu->context); | ||||
|             } | ||||
|         } else if(idx == DesktopLockMenuIndexDummy) { | ||||
|             if((dummy_mode == false) && (event->type == InputTypeShort)) { | ||||
|                 lock_menu->callback(DesktopLockMenuEventDummyModeOn, lock_menu->context); | ||||
|  | ||||
| @ -19,6 +19,7 @@ typedef struct { | ||||
|     uint8_t idx; | ||||
|     bool pin_is_set; | ||||
|     bool dummy_mode; | ||||
|     bool stealth_mode; | ||||
| } DesktopLockMenuViewModel; | ||||
| 
 | ||||
| void desktop_lock_menu_set_callback( | ||||
| @ -29,6 +30,7 @@ void desktop_lock_menu_set_callback( | ||||
| View* desktop_lock_menu_get_view(DesktopLockMenuView* lock_menu); | ||||
| void desktop_lock_menu_set_pin_state(DesktopLockMenuView* lock_menu, bool pin_is_set); | ||||
| void desktop_lock_menu_set_dummy_mode_state(DesktopLockMenuView* lock_menu, bool dummy_mode); | ||||
| void desktop_lock_menu_set_stealth_mode_state(DesktopLockMenuView* lock_menu, bool stealth_mode); | ||||
| void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx); | ||||
| DesktopLockMenuView* desktop_lock_menu_alloc(); | ||||
| void desktop_lock_menu_free(DesktopLockMenuView* lock_menu); | ||||
|  | ||||
| @ -20,9 +20,9 @@ static const uint8_t reset_sound_mask = 1 << 4; | ||||
| static const uint8_t reset_display_mask = 1 << 5; | ||||
| static const uint8_t reset_blink_mask = 1 << 6; | ||||
| 
 | ||||
| void notification_vibro_on(); | ||||
| void notification_vibro_on(bool force); | ||||
| void notification_vibro_off(); | ||||
| void notification_sound_on(float freq, float volume); | ||||
| void notification_sound_on(float freq, float volume, bool force); | ||||
| void notification_sound_off(); | ||||
| 
 | ||||
| uint8_t notification_settings_get_display_brightness(NotificationApp* app, uint8_t value); | ||||
| @ -141,17 +141,21 @@ uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app) { | ||||
| } | ||||
| 
 | ||||
| // generics
 | ||||
| void notification_vibro_on() { | ||||
|     furi_hal_vibro_on(true); | ||||
| void notification_vibro_on(bool force) { | ||||
|     if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) { | ||||
|         furi_hal_vibro_on(true); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void notification_vibro_off() { | ||||
|     furi_hal_vibro_on(false); | ||||
| } | ||||
| 
 | ||||
| void notification_sound_on(float freq, float volume) { | ||||
|     if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) { | ||||
|         furi_hal_speaker_start(freq, volume); | ||||
| void notification_sound_on(float freq, float volume, bool force) { | ||||
|     if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) { | ||||
|         if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) { | ||||
|             furi_hal_speaker_start(freq, volume); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -174,6 +178,8 @@ void notification_process_notification_message( | ||||
|     NotificationApp* app, | ||||
|     NotificationAppMessage* message) { | ||||
|     uint32_t notification_message_index = 0; | ||||
|     bool force_volume = false; | ||||
|     bool force_vibro = false; | ||||
|     const NotificationMessage* notification_message; | ||||
|     notification_message = (*message->sequence)[notification_message_index]; | ||||
| 
 | ||||
| @ -269,7 +275,7 @@ void notification_process_notification_message( | ||||
|             break; | ||||
|         case NotificationMessageTypeVibro: | ||||
|             if(notification_message->data.vibro.on) { | ||||
|                 if(vibro_setting) notification_vibro_on(); | ||||
|                 if(vibro_setting) notification_vibro_on(force_vibro); | ||||
|             } else { | ||||
|                 notification_vibro_off(); | ||||
|             } | ||||
| @ -278,7 +284,8 @@ void notification_process_notification_message( | ||||
|         case NotificationMessageTypeSoundOn: | ||||
|             notification_sound_on( | ||||
|                 notification_message->data.sound.frequency, | ||||
|                 notification_message->data.sound.volume * speaker_volume_setting); | ||||
|                 notification_message->data.sound.volume * speaker_volume_setting, | ||||
|                 force_volume); | ||||
|             reset_mask |= reset_sound_mask; | ||||
|             break; | ||||
|         case NotificationMessageTypeSoundOff: | ||||
| @ -307,9 +314,11 @@ void notification_process_notification_message( | ||||
|             break; | ||||
|         case NotificationMessageTypeForceSpeakerVolumeSetting: | ||||
|             speaker_volume_setting = notification_message->data.forced_settings.speaker_volume; | ||||
|             force_volume = true; | ||||
|             break; | ||||
|         case NotificationMessageTypeForceVibroSetting: | ||||
|             vibro_setting = notification_message->data.forced_settings.vibro; | ||||
|             force_vibro = true; | ||||
|             break; | ||||
|         case NotificationMessageTypeForceDisplayBrightnessSetting: | ||||
|             display_brightness_setting = | ||||
|  | ||||
| @ -157,18 +157,33 @@ static NotificationAppSettings* alloc_settings() { | ||||
|     variable_item_set_current_value_index(item, value_index); | ||||
|     variable_item_set_current_value_text(item, backlight_text[value_index]); | ||||
| 
 | ||||
|     item = variable_item_list_add( | ||||
|         app->variable_item_list, "Volume", VOLUME_COUNT, volume_changed, app); | ||||
|     value_index = | ||||
|         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_text(item, volume_text[value_index]); | ||||
|     if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) { | ||||
|         item = variable_item_list_add(app->variable_item_list, "Volume", 1, NULL, app); | ||||
|         value_index = 0; | ||||
|         variable_item_set_current_value_index(item, value_index); | ||||
|         variable_item_set_current_value_text(item, "Stealth"); | ||||
|     } else { | ||||
|         item = variable_item_list_add( | ||||
|             app->variable_item_list, "Volume", VOLUME_COUNT, volume_changed, app); | ||||
|         value_index = 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_text(item, volume_text[value_index]); | ||||
|     } | ||||
| 
 | ||||
|     item = | ||||
|         variable_item_list_add(app->variable_item_list, "Vibro", VIBRO_COUNT, vibro_changed, app); | ||||
|     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_text(item, vibro_text[value_index]); | ||||
|     if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) { | ||||
|         item = variable_item_list_add(app->variable_item_list, "Vibro", 1, NULL, app); | ||||
|         value_index = 0; | ||||
|         variable_item_set_current_value_index(item, value_index); | ||||
|         variable_item_set_current_value_text(item, "Stealth"); | ||||
|     } else { | ||||
|         item = variable_item_list_add( | ||||
|             app->variable_item_list, "Vibro", VIBRO_COUNT, vibro_changed, app); | ||||
|         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_text(item, vibro_text[value_index]); | ||||
|     } | ||||
| 
 | ||||
|     app->view_dispatcher = view_dispatcher_alloc(); | ||||
|     view_dispatcher_enable_queue(app->view_dispatcher); | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								assets/icons/StatusBar/Muted_8x8.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/icons/StatusBar/Muted_8x8.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 3.5 KiB | 
| @ -31,6 +31,7 @@ typedef enum { | ||||
|     FuriHalRtcFlagC2Update = (1 << 3), | ||||
|     FuriHalRtcFlagHandOrient = (1 << 4), | ||||
|     FuriHalRtcFlagLegacySleep = (1 << 5), | ||||
|     FuriHalRtcFlagStealthMode = (1 << 6), | ||||
| } FuriHalRtcFlag; | ||||
| 
 | ||||
| typedef enum { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Astra
						Astra