Просмотр исходного кода

[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>
Astra 2 лет назад
Родитель
Сommit
74fe003f8b

+ 29 - 0
applications/services/desktop/desktop.c

@@ -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) &&

+ 2 - 0
applications/services/desktop/desktop_i.h

@@ -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);

+ 12 - 0
applications/services/desktop/scenes/desktop_scene_lock_menu.c

@@ -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;
         }

+ 2 - 0
applications/services/desktop/views/desktop_events.h

@@ -34,6 +34,8 @@ typedef enum {
     DesktopLockMenuEventPinLock,
     DesktopLockMenuEventDummyModeOn,
     DesktopLockMenuEventDummyModeOff,
+    DesktopLockMenuEventStealthModeOn,
+    DesktopLockMenuEventStealthModeOff,
 
     DesktopAnimationEventCheckAnimation,
     DesktopAnimationEventNewIdleAnimation,

+ 29 - 9
applications/services/desktop/views/desktop_view_lock_menu.c

@@ -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);

+ 2 - 0
applications/services/desktop/views/desktop_view_lock_menu.h

@@ -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);

+ 18 - 9
applications/services/notification/notification_app.c

@@ -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 =

+ 27 - 12
applications/settings/notification_settings/notification_settings_app.c

@@ -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]);
-
-    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, "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]);
+    }
+
+    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


+ 1 - 0
firmware/targets/furi_hal_include/furi_hal_rtc.h

@@ -31,6 +31,7 @@ typedef enum {
     FuriHalRtcFlagC2Update = (1 << 3),
     FuriHalRtcFlagHandOrient = (1 << 4),
     FuriHalRtcFlagLegacySleep = (1 << 5),
+    FuriHalRtcFlagStealthMode = (1 << 6),
 } FuriHalRtcFlag;
 
 typedef enum {