feat(core/eckhart): two types of auto lock delay in device menu
What changed, and why it matters
This commit is a user-interface feature change for the Trezor hardware wallet. It splits the single 'auto-lock delay' setting in the device menu into two separate entries: one for when the device is on battery/wireless charger and one for when it is connected to USB. There is no indication in the commit that this fixes a security bug or changes any security-critical behavior; it is purely a UI/UX update.
No security action required. This is a normal feature commit. If reviewing for release readiness, note that the second auto-lock value is mocked to the same value as the first (TODO in `device_menu.py`), so the functional split is not yet complete.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change refactors the device menu API so that auto_lock_delay is passed as a tuple of two strings ([TString; 2] / tuple[str, str]) instead of a single string. It adds a new ‘AutoLock’ submenu in the Eckhart layout, with distinct menu result variants AutoLockBattery and AutoLockUSB. The Python side (device_menu.py) currently returns the same formatted delay for both values (noted in a TODO comment). All other layouts (Bolt, Caesar, Delizia) only update their type signatures and do not implement the new submenu. Translation keys and qstr definitions are updated accordingly. No security-sensitive logic is modified.
Changed components
core/embed/rust/src/ui/layout_eckhart/firmware/device_menu_screen.rscore/embed/rust/src/ui/api/firmware_micropython.rscore/embed/rust/src/ui/layout/device_menu_result.rscore/src/apps/homescreen/device_menu.pycore/embed/rust/src/ui/ui_firmware.rscore/embed/rust/src/ui/layout_bolt/ui_firmware.rscore/embed/rust/src/ui/layout_caesar/ui_firmware.rscore/embed/rust/src/ui/layout_delizia/ui_firmware.rscore/embed/rust/src/ui/layout_eckhart/ui_firmware.rscore/embed/rust/src/ui/layout_eckhart/component_msg_obj.rscore/translations/en.jsoncore/translations/order.jsoncore/translations/signatures.jsoncore/mocks/generated/trezorui_api.pyicore/mocks/trezortranslate_keys.pyicore/embed/rust/librust_qstr.hcore/embed/rust/src/translations/generated/translated_string.rsInspect captured patch +108 / −42
diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h
index afb91860..97670d09 100644
--- a/core/embed/rust/librust_qstr.h
+++ b/core/embed/rust/librust_qstr.h
@@ -18,7 +18,8 @@ static void _librust_qstrs(void) {
MP_QSTR_;
MP_QSTR_ATTACHED;
MP_QSTR_AttachType;
- MP_QSTR_AutoLockDelay;
+ MP_QSTR_AutoLockBattery;
+ MP_QSTR_AutoLockUSB;
MP_QSTR_BACK;
MP_QSTR_BLEIF;
MP_QSTR_BacklightLevels;
@@ -126,6 +127,8 @@ static void _librust_qstrs(void) {
MP_QSTR_authenticate__header;
MP_QSTR_auto_lock__change_template;
MP_QSTR_auto_lock__description;
+ MP_QSTR_auto_lock__on_battery;
+ MP_QSTR_auto_lock__on_usb;
MP_QSTR_auto_lock__title;
MP_QSTR_auto_lock__turned_on;
MP_QSTR_auto_lock_delay;
diff --git a/core/embed/rust/src/translations/generated/translated_string.rs b/core/embed/rust/src/translations/generated/translated_string.rs
index f087c907..8f7b1397 100644
--- a/core/embed/rust/src/translations/generated/translated_string.rs
+++ b/core/embed/rust/src/translations/generated/translated_string.rs
@@ -1543,6 +1543,8 @@ pub enum TranslatedString {
thp__pair_name = 1151, // {"Bolt": "", "Caesar": "", "Delizia": "", "Eckhart": "{0} is your Trezor's name."}
thp__pair_new_device = 1152, // {"Bolt": "", "Caesar": "", "Delizia": "", "Eckhart": "Pair with new device"}
tutorial__power = 1153, // "Use the power button on the side to turn your device on or off."
+ auto_lock__on_battery = 1154, // "on battery / wireless charger"
+ auto_lock__on_usb = 1155, // "connected to USB"
}
impl TranslatedString {
@@ -3523,6 +3525,8 @@ impl TranslatedString {
#[cfg(feature = "layout_eckhart")]
(Self::thp__pair_new_device, "Pair with new device"),
(Self::tutorial__power, "Use the power button on the side to turn your device on or off."),
+ (Self::auto_lock__on_battery, "on battery / wireless charger"),
+ (Self::auto_lock__on_usb, "connected to USB"),
];
#[cfg(feature = "micropython")]
@@ -3556,6 +3560,8 @@ impl TranslatedString {
(Qstr::MP_QSTR_authenticate__header, Self::authenticate__header),
(Qstr::MP_QSTR_auto_lock__change_template, Self::auto_lock__change_template),
(Qstr::MP_QSTR_auto_lock__description, Self::auto_lock__description),
+ (Qstr::MP_QSTR_auto_lock__on_battery, Self::auto_lock__on_battery),
+ (Qstr::MP_QSTR_auto_lock__on_usb, Self::auto_lock__on_usb),
(Qstr::MP_QSTR_auto_lock__title, Self::auto_lock__title),
(Qstr::MP_QSTR_auto_lock__turned_on, Self::auto_lock__turned_on),
(Qstr::MP_QSTR_backup__can_back_up_anytime, Self::backup__can_back_up_anytime),
diff --git a/core/embed/rust/src/ui/api/firmware_micropython.rs b/core/embed/rust/src/ui/api/firmware_micropython.rs
index 7fdde105..122d42b8 100644
--- a/core/embed/rust/src/ui/api/firmware_micropython.rs
+++ b/core/embed/rust/src/ui/api/firmware_micropython.rs
@@ -943,9 +943,11 @@ extern "C" fn new_show_device_menu(n_args: usize, args: *const Obj, kwargs: *mut
let connected_idx: Option<u8> =
kwargs.get(Qstr::MP_QSTR_connected_idx)?.try_into_option()?;
let pin_code: Option<bool> = kwargs.get(Qstr::MP_QSTR_pin_code)?.try_into_option()?;
- let auto_lock_delay: Option<TString> = kwargs
+ let auto_lock_delay: Option<[TString; 2]> = kwargs
.get(Qstr::MP_QSTR_auto_lock_delay)?
- .try_into_option()?;
+ .try_into_option()?
+ .map(util::iter_into_array)
+ .transpose()?;
let wipe_code: Option<bool> = kwargs.get(Qstr::MP_QSTR_wipe_code)?.try_into_option()?;
let check_backup: bool = kwargs.get(Qstr::MP_QSTR_check_backup)?.try_into()?;
let device_name: Option<TString> =
@@ -1920,7 +1922,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// paired_devices: Iterable[str],
/// connected_idx: int | None,
/// pin_code: bool | None,
- /// auto_lock_delay: str | None,
+ /// auto_lock_delay: tuple[str, str] | None,
/// wipe_code: bool | None,
/// check_backup: bool,
/// device_name: str | None,
@@ -2140,7 +2142,8 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// DeviceUnpairAll: ClassVar[DeviceMenuResult]
/// PinCode: ClassVar[DeviceMenuResult]
/// PinRemove: ClassVar[DeviceMenuResult]
- /// AutoLockDelay: ClassVar[DeviceMenuResult]
+ /// AutoLockBattery: ClassVar[DeviceMenuResult]
+ /// AutoLockUSB: ClassVar[DeviceMenuResult]
/// WipeCode: ClassVar[DeviceMenuResult]
/// WipeRemove: ClassVar[DeviceMenuResult]
/// CheckBackup: ClassVar[DeviceMenuResult]
diff --git a/core/embed/rust/src/ui/layout/device_menu_result.rs b/core/embed/rust/src/ui/layout/device_menu_result.rs
index 8c6d3136..667df1b0 100644
--- a/core/embed/rust/src/ui/layout/device_menu_result.rs
+++ b/core/embed/rust/src/ui/layout/device_menu_result.rs
@@ -17,7 +17,8 @@ pub static DEVICE_UNPAIR_ALL: SimpleTypeObj = SimpleTypeObj::new(&DEVICE_MENU_RE
// Security menu
pub static PIN_CODE: SimpleTypeObj = SimpleTypeObj::new(&DEVICE_MENU_RESULT_BASE_TYPE);
pub static PIN_REMOVE: SimpleTypeObj = SimpleTypeObj::new(&DEVICE_MENU_RESULT_BASE_TYPE);
-pub static AUTO_LOCK_DELAY: SimpleTypeObj = SimpleTypeObj::new(&DEVICE_MENU_RESULT_BASE_TYPE);
+pub static AUTO_LOCK_BATTERY: SimpleTypeObj = SimpleTypeObj::new(&DEVICE_MENU_RESULT_BASE_TYPE);
+pub static AUTO_LOCK_USB: SimpleTypeObj = SimpleTypeObj::new(&DEVICE_MENU_RESULT_BASE_TYPE);
pub static WIPE_CODE: SimpleTypeObj = SimpleTypeObj::new(&DEVICE_MENU_RESULT_BASE_TYPE);
pub static WIPE_REMOVE: SimpleTypeObj = SimpleTypeObj::new(&DEVICE_MENU_RESULT_BASE_TYPE);
pub static CHECK_BACKUP: SimpleTypeObj = SimpleTypeObj::new(&DEVICE_MENU_RESULT_BASE_TYPE);
@@ -45,7 +46,8 @@ static DEVICE_MENU_RESULT_TYPE: Type = obj_type! {
Qstr::MP_QSTR_DeviceUnpairAll => DEVICE_UNPAIR_ALL.as_obj(),
Qstr::MP_QSTR_PinCode => PIN_CODE.as_obj(),
Qstr::MP_QSTR_PinRemove => PIN_REMOVE.as_obj(),
- Qstr::MP_QSTR_AutoLockDelay => AUTO_LOCK_DELAY.as_obj(),
+ Qstr::MP_QSTR_AutoLockBattery => AUTO_LOCK_BATTERY.as_obj(),
+ Qstr::MP_QSTR_AutoLockUSB => AUTO_LOCK_USB.as_obj(),
Qstr::MP_QSTR_WipeCode => WIPE_CODE.as_obj(),
Qstr::MP_QSTR_WipeRemove => WIPE_REMOVE.as_obj(),
Qstr::MP_QSTR_CheckBackup => CHECK_BACKUP.as_obj(),
diff --git a/core/embed/rust/src/ui/layout_bolt/ui_firmware.rs b/core/embed/rust/src/ui/layout_bolt/ui_firmware.rs
index 7adb4483..5cf1e05d 100644
--- a/core/embed/rust/src/ui/layout_bolt/ui_firmware.rs
+++ b/core/embed/rust/src/ui/layout_bolt/ui_firmware.rs
@@ -939,7 +939,7 @@ impl FirmwareUI for UIBolt {
_paired_devices: heapless::Vec<TString<'static>, MAX_PAIRED_DEVICES>,
_connected_idx: Option<u8>,
_pin_code: Option<bool>,
- _auto_lock_delay: Option<TString<'static>>,
+ _auto_lock_delay: Option<[TString<'static>; 2]>,
_wipe_code: Option<bool>,
_check_backup: bool,
_device_name: Option<TString<'static>>,
diff --git a/core/embed/rust/src/ui/layout_caesar/ui_firmware.rs b/core/embed/rust/src/ui/layout_caesar/ui_firmware.rs
index 0cd5ee30..28c5caaf 100644
--- a/core/embed/rust/src/ui/layout_caesar/ui_firmware.rs
+++ b/core/embed/rust/src/ui/layout_caesar/ui_firmware.rs
@@ -1136,7 +1136,7 @@ impl FirmwareUI for UICaesar {
_paired_devices: heapless::Vec<TString<'static>, MAX_PAIRED_DEVICES>,
_connected_idx: Option<u8>,
_pin_code: Option<bool>,
- _auto_lock_delay: Option<TString<'static>>,
+ _auto_lock_delay: Option<[TString<'static>; 2]>,
_wipe_code: Option<bool>,
_check_backup: bool,
_device_name: Option<TString<'static>>,
diff --git a/core/embed/rust/src/ui/layout_delizia/ui_firmware.rs b/core/embed/rust/src/ui/layout_delizia/ui_firmware.rs
index 3ff86319..c2414c0a 100644
--- a/core/embed/rust/src/ui/layout_delizia/ui_firmware.rs
+++ b/core/embed/rust/src/ui/layout_delizia/ui_firmware.rs
@@ -1021,7 +1021,7 @@ impl FirmwareUI for UIDelizia {
_paired_devices: heapless::Vec<TString<'static>, MAX_PAIRED_DEVICES>,
_connected_idx: Option<u8>,
_pin_code: Option<bool>,
- _auto_lock_delay: Option<TString<'static>>,
+ _auto_lock_delay: Option<[TString<'static>; 2]>,
_wipe_code: Option<bool>,
_check_backup: bool,
_device_name: Option<TString<'static>>,
diff --git a/core/embed/rust/src/ui/layout_eckhart/component_msg_obj.rs b/core/embed/rust/src/ui/layout_eckhart/component_msg_obj.rs
index 2d9f6791..7c2ec97a 100644
--- a/core/embed/rust/src/ui/layout_eckhart/component_msg_obj.rs
+++ b/core/embed/rust/src/ui/layout_eckhart/component_msg_obj.rs
@@ -169,7 +169,8 @@ impl ComponentMsgObj for DeviceMenuScreen {
// Security menu
DeviceMenuMsg::PinCode => Ok(PIN_CODE.as_obj()),
DeviceMenuMsg::PinRemove => Ok(PIN_REMOVE.as_obj()),
- DeviceMenuMsg::AutoLockDelay => Ok(AUTO_LOCK_DELAY.as_obj()),
+ DeviceMenuMsg::AutoLockBattery => Ok(AUTO_LOCK_BATTERY.as_obj()),
+ DeviceMenuMsg::AutoLockUSB => Ok(AUTO_LOCK_USB.as_obj()),
DeviceMenuMsg::WipeCode => Ok(WIPE_CODE.as_obj()),
DeviceMenuMsg::WipeRemove => Ok(WIPE_REMOVE.as_obj()),
DeviceMenuMsg::CheckBackup => Ok(CHECK_BACKUP.as_obj()),
diff --git a/core/embed/rust/src/ui/layout_eckhart/firmware/device_menu_screen.rs b/core/embed/rust/src/ui/layout_eckhart/firmware/device_menu_screen.rs
index 2403b047..07b32631 100644
--- a/core/embed/rust/src/ui/layout_eckhart/firmware/device_menu_screen.rs
+++ b/core/embed/rust/src/ui/layout_eckhart/firmware/device_menu_screen.rs
@@ -49,6 +49,7 @@ pub enum DeviceMenuId {
Settings,
Security,
PinCode,
+ AutoLock,
WipeCode,
Device,
Power,
@@ -63,9 +64,10 @@ impl TryFrom<u8> for DeviceMenuId {
2 => Ok(DeviceMenuId::Settings),
3 => Ok(DeviceMenuId::Security),
4 => Ok(DeviceMenuId::PinCode),
- 5 => Ok(DeviceMenuId::WipeCode),
- 6 => Ok(DeviceMenuId::Device),
- 7 => Ok(DeviceMenuId::Power),
+ 5 => Ok(DeviceMenuId::AutoLock),
+ 6 => Ok(DeviceMenuId::WipeCode),
+ 7 => Ok(DeviceMenuId::Device),
+ 8 => Ok(DeviceMenuId::Power),
_ => Err(()),
}
}
@@ -86,7 +88,7 @@ impl From<DeviceMenuId> for usize {
}
// FIXME: use mem::variant_count when it becomes stable
-const MAX_SUBMENUS: usize = 8;
+const MAX_SUBMENUS: usize = 9;
// submenus, device screens, regulatory and about screens
const MAX_SUBSCREENS: usize = MAX_SUBMENUS + MAX_PAIRED_DEVICES + 2;
@@ -123,7 +125,8 @@ pub enum DeviceMenuMsg {
// Security menu
PinCode,
PinRemove,
- AutoLockDelay,
+ AutoLockBattery,
+ AutoLockUSB,
WipeCode,
WipeRemove,
CheckBackup,
@@ -226,12 +229,14 @@ impl MenuItem {
struct Submenu {
show_battery: bool,
items: Vec<MenuItem, MEDIUM_MENU_ITEMS>,
+ subtitle: Option<TString<'static>>,
}
impl Submenu {
pub fn new(items: Vec<MenuItem, MEDIUM_MENU_ITEMS>) -> Self {
Self {
show_battery: false,
+ subtitle: None,
items,
}
}
@@ -240,6 +245,11 @@ impl Submenu {
self.show_battery = true;
self
}
+
+ pub fn with_subtitle(mut self, subtitle: TString<'static>) -> Self {
+ self.subtitle = Some(subtitle);
+ self
+ }
}
// Each subscreen of the DeviceMenuScreen is one of these
@@ -299,7 +309,7 @@ impl DeviceMenuScreen {
paired_devices: Vec<TString<'static>, MAX_PAIRED_DEVICES>,
connected_idx: Option<u8>,
pin_code: Option<bool>,
- auto_lock_delay: Option<TString<'static>>,
+ auto_lock_delay: Option<[TString<'static>; 2]>,
wipe_code: Option<bool>,
check_backup: bool,
device_name: Option<TString<'static>>,
@@ -469,10 +479,29 @@ impl DeviceMenuScreen {
self.register_submenu(id, Submenu::new(items));
}
+ fn register_auto_lock_menu(&mut self, auto_lock_delay: [TString<'static>; 2]) {
+ let mut items: Vec<MenuItem, MEDIUM_MENU_ITEMS> = Vec::new();
+ let battery_delay = MenuItem::new(
+ auto_lock_delay[0],
+ Some(Action::Return(DeviceMenuMsg::AutoLockBattery)),
+ )
+ .with_subtext(Some((TR::auto_lock__on_battery.into(), None)));
+ items.add(battery_delay);
+
+ let usb_delay = MenuItem::new(
+ auto_lock_delay[1],
+ Some(Action::Return(DeviceMenuMsg::AutoLockUSB)),
+ )
+ .with_subtext(Some((TR::auto_lock__on_usb.into(), None)));
+ items.add(usb_delay);
+
+ self.register_submenu(DeviceMenuId::AutoLock, Submenu::new(items));
+ }
+
fn register_security_menu(
&mut self,
pin_code: Option<bool>,
- auto_lock_delay: Option<TString<'static>>,
+ auto_lock_delay: Option<[TString<'static>; 2]>,
wipe_code: Option<bool>,
check_backup: bool,
) {
@@ -495,9 +524,9 @@ impl DeviceMenuScreen {
}
if let Some(auto_lock_delay) = auto_lock_delay {
+ self.register_auto_lock_menu(auto_lock_delay);
let auto_lock_delay_item =
- MenuItem::return_msg(TR::auto_lock__title.into(), DeviceMenuMsg::AutoLockDelay)
- .with_subtext(Some((auto_lock_delay, None)));
+ MenuItem::go_to_submenu(TR::auto_lock__title.into(), DeviceMenuId::AutoLock);
items.add(auto_lock_delay_item);
}
@@ -710,8 +739,12 @@ impl DeviceMenuScreen {
HeaderMsg::Back,
);
}
- *self.active_screen.deref_mut() =
- ActiveScreen::Menu(VerticalMenuScreen::new(menu).with_header(header), id);
+ *self.active_screen.deref_mut() = ActiveScreen::Menu(
+ VerticalMenuScreen::new(menu)
+ .with_header(header)
+ .with_subtitle(submenu.subtitle.unwrap_or(TString::empty())),
+ id,
+ );
}
Subscreen::DeviceScreen(device, connected, _) => {
let mut menu = VerticalMenu::empty();
@@ -796,6 +829,7 @@ impl DeviceMenuScreen {
DeviceMenuId::Settings => DeviceMenuId::Root,
DeviceMenuId::Security => DeviceMenuId::Settings,
DeviceMenuId::PinCode => DeviceMenuId::Security,
+ DeviceMenuId::AutoLock => DeviceMenuId::Security,
DeviceMenuId::WipeCode => DeviceMenuId::Security,
DeviceMenuId::Device => DeviceMenuId::Settings,
DeviceMenuId::Power => DeviceMenuId::Root,
diff --git a/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs b/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs
index 1ab47be9..0d20ce89 100644
--- a/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs
+++ b/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs
@@ -1205,7 +1205,7 @@ impl FirmwareUI for UIEckhart {
paired_devices: heapless::Vec<TString<'static>, MAX_PAIRED_DEVICES>,
connected_idx: Option<u8>,
pin_code: Option<bool>,
- auto_lock_delay: Option<TString<'static>>,
+ auto_lock_delay: Option<[TString<'static>; 2]>,
wipe_code: Option<bool>,
check_backup: bool,
device_name: Option<TString<'static>>,
diff --git a/core/embed/rust/src/ui/ui_firmware.rs b/core/embed/rust/src/ui/ui_firmware.rs
index 445e3a7f..c684a626 100644
--- a/core/embed/rust/src/ui/ui_firmware.rs
+++ b/core/embed/rust/src/ui/ui_firmware.rs
@@ -366,7 +366,7 @@ pub trait FirmwareUI {
paired_devices: heapless::Vec<TString<'static>, MAX_PAIRED_DEVICES>,
connected_idx: Option<u8>,
pin_code: Option<bool>,
- auto_lock_delay: Option<TString<'static>>,
+ auto_lock_delay: Option<[TString<'static>; 2]>,
wipe_code: Option<bool>,
check_backup: bool,
device_name: Option<TString<'static>>,
diff --git a/core/mocks/generated/trezorui_api.pyi b/core/mocks/generated/trezorui_api.pyi
index bcc1a6d8..aa05f455 100644
--- a/core/mocks/generated/trezorui_api.pyi
+++ b/core/mocks/generated/trezorui_api.pyi
@@ -629,7 +629,7 @@ def show_device_menu(
paired_devices: Iterable[str],
connected_idx: int | None,
pin_code: bool | None,
- auto_lock_delay: str | None,
+ auto_lock_delay: tuple[str, str] | None,
wipe_code: bool | None,
check_backup: bool,
device_name: str | None,
@@ -870,7 +870,8 @@ class DeviceMenuResult:
DeviceUnpairAll: ClassVar[DeviceMenuResult]
PinCode: ClassVar[DeviceMenuResult]
PinRemove: ClassVar[DeviceMenuResult]
- AutoLockDelay: ClassVar[DeviceMenuResult]
+ AutoLockBattery: ClassVar[DeviceMenuResult]
+ AutoLockUSB: ClassVar[DeviceMenuResult]
WipeCode: ClassVar[DeviceMenuResult]
WipeRemove: ClassVar[DeviceMenuResult]
CheckBackup: ClassVar[DeviceMenuResult]
diff --git a/core/mocks/trezortranslate_keys.pyi b/core/mocks/trezortranslate_keys.pyi
index b483529c..a63fc7b8 100644
--- a/core/mocks/trezortranslate_keys.pyi
+++ b/core/mocks/trezortranslate_keys.pyi
@@ -31,6 +31,8 @@ class TR:
authenticate__header: str = "Authenticate device"
auto_lock__change_template: str = "Auto-lock Trezor after {0} of inactivity?"
auto_lock__description: str = "Set the time before your Trezor locks automatically."
+ auto_lock__on_battery: str = "on battery / wireless charger"
+ auto_lock__on_usb: str = "connected to USB"
auto_lock__title: str = "Auto-lock delay"
auto_lock__turned_on: str = "Auto-lock turned on"
backup__can_back_up_anytime: str = "You can back up your Trezor once, at any time."
diff --git a/core/src/apps/homescreen/device_menu.py b/core/src/apps/homescreen/device_menu.py
index d9248bf0..d0a4c9c2 100644
--- a/core/src/apps/homescreen/device_menu.py
+++ b/core/src/apps/homescreen/device_menu.py
@@ -11,15 +11,17 @@ from trezorui_api import CANCELLED, DeviceMenuResult
BLE_MAX_BONDS = 8
+# Must be in sync with the DeviceMenuId in device_menu.ui
class SubmenuId:
ROOT = const(0)
PAIR_AND_CONNECT = const(1)
SETTINGS = const(2)
SECURITY = const(3)
PIN_CODE = const(4)
- WIPE_CODE = const(5)
- DEVICE = const(6)
- POWER = const(7)
+ AUTO_LOCK = const(5)
+ WIPE_CODE = const(6)
+ DEVICE = const(7)
+ POWER = const(8)
def _get_hostname(ble_addr: bytes, hostname_map: dict[bytes, str]) -> str:
@@ -38,9 +40,19 @@ def _find_device(connected_addr: bytes | None, bonds: list[bytes]) -> int | None
return None
-async def handle_device_menu() -> None:
+def get_auto_lock_delay() -> tuple[str, str] | None:
from trezor import strings
+ if not config.has_pin():
+ return None
+ delay = storage_device.get_autolock_delay_ms()
+ # TODO: the second value is mocked by using the same value
+ formatted = strings.format_autolock_duration(delay)
+ return (formatted, formatted)
+
+
+async def handle_device_menu() -> None:
+
assert utils.USE_THP and utils.USE_BLE
from ..thp import paired_cache
@@ -72,12 +84,6 @@ async def handle_device_menu() -> None:
firmware_version = ".".join(map(str, utils.VERSION))
firmware_type = "Bitcoin-only" if utils.BITCOIN_ONLY else "Universal"
- auto_lock_delay = (
- strings.format_autolock_duration(storage_device.get_autolock_delay_ms())
- if config.has_pin()
- else None
- )
-
menu_result = await interact(
trezorui_api.show_device_menu(
init_submenu=init_submenu,
@@ -85,7 +91,7 @@ async def handle_device_menu() -> None:
paired_devices=paired_devices,
connected_idx=connected_idx,
pin_code=config.has_pin() if is_initialized else None,
- auto_lock_delay=auto_lock_delay,
+ auto_lock_delay=get_auto_lock_delay(),
wipe_code=config.has_wipe_code() if is_initialized else None,
check_backup=is_initialized,
device_name=(
@@ -215,7 +221,11 @@ async def handle_device_menu() -> None:
pass
finally:
init_submenu = SubmenuId.SECURITY
- elif menu_result is DeviceMenuResult.AutoLockDelay and config.has_pin():
+ elif (
+ menu_result
+ in (DeviceMenuResult.AutoLockUSB, DeviceMenuResult.AutoLockBattery)
+ and config.has_pin()
+ ):
from trezor.messages import ApplySettings
from apps.management.apply_settings import apply_settings
diff --git a/core/translations/en.json b/core/translations/en.json
index 0a203527..c0937cbe 100644
--- a/core/translations/en.json
+++ b/core/translations/en.json
@@ -43,6 +43,8 @@
"authenticate__header": "Authenticate device",
"auto_lock__change_template": "Auto-lock Trezor after {0} of inactivity?",
"auto_lock__description": "Set the time before your Trezor locks automatically.",
+ "auto_lock__on_battery": "on battery / wireless charger",
+ "auto_lock__on_usb": "connected to USB",
"auto_lock__title": {
"Bolt": "Auto-lock delay",
"Caesar": "Auto-lock delay",
diff --git a/core/translations/order.json b/core/translations/order.json
index 0ccbe9b6..d5a0e974 100644
--- a/core/translations/order.json
+++ b/core/translations/order.json
@@ -1152,5 +1152,7 @@
"1150": "thp__continue_on_host",
"1151": "thp__pair_name",
"1152": "thp__pair_new_device",
- "1153": "tutorial__power"
+ "1153": "tutorial__power",
+ "1154": "auto_lock__on_battery",
+ "1155": "auto_lock__on_usb"
}
diff --git a/core/translations/signatures.json b/core/translations/signatures.json
index 5d47c326..c57a0084 100644
--- a/core/translations/signatures.json
+++ b/core/translations/signatures.json
@@ -1,8 +1,8 @@
{
"current": {
- "merkle_root": "340f1b8642e284a1c31c3df08e79fbf3be01be0c491718c164bd425b0c23e16c",
- "datetime": "2025-09-12T06:33:58.713863+00:00",
- "commit": "5cef52bec8690b861c0381899df32803a3809e5e"
+ "merkle_root": "aa8c7ed0b778cf38422e8f0c20130cef39364f1736107ce5071a7d611afbc3ad",
+ "datetime": "2025-09-15T10:48:26.905920+00:00",
+ "commit": "06cbaf19d8bfbc3b9bf9e018a5f94918e6b78f03"
},
"history": [
{
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.